Archive for the ‘linux’ Category

Alpine mass delete messages

Friday, March 7th, 2014

You have new mail.

Почти не използвам локалната пощенска кутия. Всъщност единственото за което я ползвам е да следя за грешки по кроновете които работят на системата. Принципно целия STDOUT+STDERR бива изпращан по мейл на текущия потребител. STDOUT не ми трябва, понеже често си оставям някакви дебъгващи принтове тук-таме по скриптовете. За това си описвам задачите с >/dev/null. По този начин STDOUT се филтрира, и остава само STDERR. Ако искам да махна абсолютно целия изход от изпълнението правя >/dev/null 2>&1.

Ако нещо по кроновете видимо не работи, отварям пощата и чета. Обикновено я преглеждам през няколко седмици за да изтрия старите логове от крона. За това използвам alpine, понеже не ми се занимава с никакви тежки и сериозни GUI изпълнения като Thunderbird. Удобно е да се логна в ssh от където и да е и да изтараша пощенската кутия.

Днес alpine се стартира малко по-бавно и какво да гледам в пощенската кутия – 12 136 писма. Оказа се че съм написал доста тъпо един от кроновете:


*/5 * * * * cd /home/ivanatora/rilski_ezera; wget "http://www.rilskiezera.bg/meteo/rilskiezerahut.jpg" -O img_`date +\%Y-\%m-\%d_\%R`.jpg >/dev/null

Това сваля снимка от х. Рилски Езера на всеки 5 минути и по-късно си правя таймлапс със свалените изображения. Въпросът е защо така злобно ми е нафлудил пощата, при условие че STDOUT е филтриран?

Защото съм забравил че `wget` не принти съобщенията си в STDOUT, а вместо това в STDERR (факт)…

Както и да е – оправих крона, но сега проблема беше как да изчистя пощенската кутия с alpine. Обикновено трия пощата по следния начин – отивам върху първото писмо и задържам D. Това го маркира за изтриване (което ще се случи след затваряне на клиента) и преминава към следващото. Това минава през съобщенията едно след друго и нормално за няколко секунди изчиствам цялата кутия. Само че в случая с 12 хиляди писма това би ми отнело към 20 минути набиране върху D-то.

Поблъсках се малко и намерих процедурата за изтриване на всички съобщения:

1. В INBOX се натиска `;` за Select messages
2. Натиска се A за Select all.
3. Натиска се A за Apply command
4. Натиска се D за Delete

След това се излиза нормално от клиента с ^X и писмата се изтриват.

Linux + scheduled tasks

Monday, March 25th, 2013

Може да ви се наложи да стартирате команда по часовник или по време когато не сте на машината.
Единият вариант който се използва е cron, но това е по-скоро за задачи, които се повтарят във времето. Няма да го разлеждаме, тъй като нета е пълен с примери и на всеки рано или късно му се е налагало да си блъска главата с него 🙂

По-интересното е да направим единично стартиране на задача по зададено време.

В Линукс това става много лесно с командата `at`:


(19:18:49)[ivanatora@~]$ at 19:20
warning: commands will be executed using /bin/sh
at> beep
at>
job 17 at Mon Mar 25 19:20:00 2013

Забележка: това <EOT> предполагам че е end-of-terminal и се получава с CTRL+D.
В случая задачата която ще се стартира е `beep`. Можете да напишете цял скрипт в промпта на `at` или да укажете външен файл който съдържа скриптираните задачи чрез `at [-f file]`. Отбележете че интерпретаторът, с който се изпълнява скрипта в случая е /bin/sh – това ще ви се отрази ако искате да скриптирате по-сложни задачи използвайки вградените възможности. Естествено, нищо не ви пречи да стартирате скрипт писан на какъвто и да е език:


(19:23:46)[ivanatora@~]$ at 19:50
warning: commands will be executed using /bin/sh
at> php /home/ivanatora/test.php
at>
job 18 at Mon Mar 25 19:50:00 2013

Списък с текущите активни задачи може да видите с `atq`:


(19:24:02)[ivanatora@~]$ atq
18 Mon Mar 25 19:50:00 2013 a ivanatora

Може да се зачудите къде отиде задача 17? Ами тя изтече докато напиша тези редове 😉

Може да изтривате задачи от списъка с `atrm`:


(19:25:35)[ivanatora@~]$ atrm 18
(19:26:13)[ivanatora@~]$ atq
(19:26:37)[ivanatora@~]$

Може да преглеждате с детайли определена задача с `at [-c job]`:

(19:27:20)[ivanatora@~]$ at 19:30
warning: commands will be executed using /bin/sh
at> beep
at>
job 19 at Mon Mar 25 19:30:00 2013
(19:27:37)[ivanatora@~]$ at -c 19
#!/bin/sh
# atrun uid=1000 gid=1000
# mail ivanatora 0
umask 2
SSH_AGENT_PID=2367; export SSH_AGENT_PID
GPG_AGENT_INFO=/tmp/gpg-xsDFU4/S.gpg-agent:2368:1; export GPG_AGENT_INFO
XDG_SESSION_COOKIE=4784344ffacd7f8cf96108324bae42fb-1364229708.104884-44687589; export XDG_SESSION_COOKIE
WINDOWID=37748745; export WINDOWID
GNOME_KEYRING_CONTROL=/tmp/keyring-bylSRi; export GNOME_KEYRING_CONTROL
GTK_MODULES=canberra-gtk-module; export GTK_MODULES
USER=ivanatora; export USER
LS_COLORS=rs=0:di=01\;34:ln=01\;36:mh=00:pi=40\;33:so=01\;35:do=01\;35:bd=40\;33\;01:cd=40\;33\;01:or=40\;31\;01:su=37\;41:sg=30\;43:ca=30\;41:tw=30\;42:ow=34\;42:st=37\;44:ex=01\;32:\*.tar=01\;31:\*.tgz=01\;31:\*.arj=01\;31:\*.taz=01\;31:\*.lzh=01\;31:\*.lzma=01\;31:\*.tlz=01\;31:\*.txz=01\;31:\*.zip=01\;31:\*.z=01\;31:\*.Z=01\;31:\*.dz=01\;31:\*.gz=01\;31:\*.lz=01\;31:\*.xz=01\;31:\*.bz2=01\;31:\*.bz=01\;31:\*.tbz=01\;31:\*.tbz2=01\;31:\*.tz=01\;31:\*.deb=01\;31:\*.rpm=01\;31:\*.jar=01\;31:\*.war=01\;31:\*.ear=01\;31:\*.sar=01\;31:\*.rar=01\;31:\*.ace=01\;31:\*.zoo=01\;31:\*.cpio=01\;31:\*.7z=01\;31:\*.rz=01\;31:\*.jpg=01\;35:\*.jpeg=01\;35:\*.gif=01\;35:\*.bmp=01\;35:\*.pbm=01\;35:\*.pgm=01\;35:\*.ppm=01\;35:\*.tga=01\;35:\*.xbm=01\;35:\*.xpm=01\;35:\*.tif=01\;35:\*.tiff=01\;35:\*.png=01\;35:\*.svg=01\;35:\*.svgz=01\;35:\*.mng=01\;35:\*.pcx=01\;35:\*.mov=01\;35:\*.mpg=01\;35:\*.mpeg=01\;35:\*.m2v=01\;35:\*.mkv=01\;35:\*.webm=01\;35:\*.ogm=01\;35:\*.mp4=01\;35:\*.m4v=01\;35:\*.mp4v=01\;35:\*.vob=01\;35:\*.qt=01\;35:\*.nuv=01\;35:\*.wmv=01\;35:\*.asf=01\;35:\*.rm=01\;35:\*.rmvb=01\;35:\*.flc=01\;35:\*.avi=01\;35:\*.fli=01\;35:\*.flv=01\;35:\*.gl=01\;35:\*.dl=01\;35:\*.xcf=01\;35:\*.xwd=01\;35:\*.yuv=01\;35:\*.cgm=01\;35:\*.emf=01\;35:\*.axv=01\;35:\*.anx=01\;35:\*.ogv=01\;35:\*.ogx=01\;35:\*.aac=00\;36:\*.au=00\;36:\*.flac=00\;36:\*.mid=00\;36:\*.midi=00\;36:\*.mka=00\;36:\*.mp3=00\;36:\*.mpc=00\;36:\*.ogg=00\;36:\*.ra=00\;36:\*.wav=00\;36:\*.axa=00\;36:\*.oga=00\;36:\*.spx=00\;36:\*.xspf=00\;36:; export LS_COLORS
XDG_SESSION_PATH=/org/freedesktop/DisplayManager/Session0; export XDG_SESSION_PATH
XDG_SEAT_PATH=/org/freedesktop/DisplayManager/Seat0; export XDG_SEAT_PATH
SSH_AUTH_SOCK=/tmp/ssh-UytBrOmq2318/agent.2318; export SSH_AUTH_SOCK
DEFAULTS_PATH=/usr/share/gconf/fluxbox.default.path; export DEFAULTS_PATH
XDG_CONFIG_DIRS=/etc/xdg/xdg-fluxbox:/etc/xdg; export XDG_CONFIG_DIRS
DESKTOP_SESSION=fluxbox; export DESKTOP_SESSION
PATH=/home/ivanatora/bin:/usr/lib/lightdm/lightdm:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/home/ivanatora/bin/; export PATH
PWD=/home/ivanatora; export PWD
GNOME_KEYRING_PID=2307; export GNOME_KEYRING_PID
LANG=en_US.UTF-8; export LANG
MANDATORY_PATH=/usr/share/gconf/fluxbox.mandatory.path; export MANDATORY_PATH
UBUNTU_MENUPROXY=libappmenu.so; export UBUNTU_MENUPROXY
PS1=\\[\\033[1\;34m\\]\(\\t\)\\[\\033[0m\\][\\u@\\[\\033[1\;33m\\]\\w\\[\\033[0m\\]]\\\$\ ; export PS1
GDMSESSION=fluxbox; export GDMSESSION
SPEECHD_PORT=7560; export SPEECHD_PORT
COLORFGBG=15\;default; export COLORFGBG
HOME=/home/ivanatora; export HOME
SHLVL=2; export SHLVL
LOGNAME=ivanatora; export LOGNAME
DBUS_SESSION_BUS_ADDRESS=unix:abstract=/tmp/dbus-rCyQHFVg4i,guid=31de69d47f7c412295741b5100000041; export DBUS_SESSION_BUS_ADDRESS
XDG_DATA_DIRS=/usr/share/fluxbox:/usr/local/share/:/usr/share/; export XDG_DATA_DIRS
LESSOPEN=\|\ /usr/bin/lesspipe\ %s; export LESSOPEN
BROWSER=firefox; export BROWSER
LESSCLOSE=/usr/bin/lesspipe\ %s\ %s; export LESSCLOSE
COLORTERM=rxvt-xpm; export COLORTERM
XAUTHORITY=/home/ivanatora/.Xauthority; export XAUTHORITY
cd /home/ivanatora || {
echo 'Execution directory inaccessible' >&2
exit 1
}
beep

 

Ау, уау, какво стана? Къде е задачата?

Задачата е най-отдолу, но за да стигне до нея `at` зарежда доста от променливите на обкръжението. Който е писал и дебъгвал крон задачи знае колко е досадно да разчиташ на определена променлива от средата, а тя да не е това което трябва…И въпреки всичкото това зареждане тук ни липсва една важна променлива, която ако сетнем ръчно ни отваря нови хоризонти. А именно – DISPLAY. По подразбиране дефаултния дисплей е “:0.0” и ако го използваме, може да стартираме задача, която работи с Х-а.

Една примерна грубa елементарна напомнянка:


(19:34:37)[ivanatora@~]$ at 19:36
warning: commands will be executed using /bin/sh
at> beep
at> DISPLAY=:0.0 xmessage "remember to eat dinner!"
at>
job 23 at Mon Mar 25 19:36:00 2013

Възможните формати за подаване на времето за стартиране е доста обширен и може да го видите в /usr/share/doc/at/timespec

Watermark Signature

Wednesday, April 18th, 2012

Поставяне на воден знак

Обикновено водния знак може да бъде два вида:
* текст, който се изписва върху снимката или
* картинка която се наслагва отгоре.

Всеки може да хване произволен шрифт от нета и да си напише името. Нека сме по-оригинални и да си направим воден знак, който никой друг не може да има – да се подпишем 🙂

Намерете хубав химикал – трябва да пише равномерно и да не пуска мастилото на капки. Изберете хартия – може да е чисто бял лист, може да има редове – зависи какъв ефект желаете да постигнете. Хартията не е необходимо да е перфектно искряща бяла. И жълтеникава да е – после ще се оправи. Подпишете се няколко пъти. Когато имате няколко добри резултата можете да извадите фотоапарата.

Сложете го на ръчен фокус като го забиете на възможно най-близкото разстояние. Обектива – в най-дългия край. Целта е да получите голямо и ясно изображение на подписа. Пуснете си live view с най-голямото увеличение за да следите как е фокуса и премествайте леко назад-напред апарата докато фокуса стане перфектен. Снимайте със светкавица като използвате най-голямата възможна разделителна способност.

Следва лека обработка. Аз съм ползвал GIMP, но нещата не са по-различни в Photoshop или всеки друг свестен редактор.
* кропваме избрания подпис
* вдигаме контраста и намаляме яркостта – целта е да смачкаме цветовете и да получим открояващо се монохромно изображение (не прекаляваме с яркостта, защото по някое време ще почнем да виждаме писаното отзад на листа 🙂 )


* ако е нужно премахваме всички цветове (desaturate)
* по желание минаваме редовете с една бяла четка
* по желание удебеляваме подписа – избираме всичко по черен цвят, увеличаваме селекцията с 1-2-3 пиксела и наливаме с черната кофа
* минаваме с бялата четка и оправяме ако са се появили разни дефекти
* ако искаме да накривим нещо (или да оправим кривина) ползваме Filters -> Distorts -> Curve Bend

На този етап би трябвало да имате черно-бяло изображение, в което единия цвят е фона, а другия – подписа. Сега да помислим как ще изглежда водния знак върху произволна снимка (а ще очакваме за в бъдеще да има много снимки подпечатани с него). Ако изкараме подписа с бял цвят, ще изглежда добре върху тъмен фон, но не и върху светъл. Ако го изкараме с черен цвят – обратно. Едно възможно решение е да му сложим полупрозрачен фон, който да го откроява:
* добавяме Alpha слой към изображението (ако вече няма такъв)
* Layers -> Transparency -> Color to Alpha – и правим фоновия цвят (белия) да е прозрачен
* правим един нов слой и го позиционираме под основата
* правим една правоъгълна селекция със заоблени краища върху подписа и я наливаме с цвят обратен на цвета на текста
* слагаме прозрачност на втория слой на 50% или по усмотрение
* изравняваме изображението и го запазваме в PNG формат (заради прозрачностите)

Вече имаме водния знак, който ще ни стане запазена марка. За да го ползваме върху снимка, обаче може би ще трябва да го посмалим малко – при мен изображението беше с размери 1700х400. Запазете оригиналния файл все пак.

От тук натам можем да отворим снимката, която ще маркираме, да добавим изображението с водния знак отгоре и да запазим новия вариант (пазете си оригиналите на снимките отделно). Но за да е по-интересно, нека автоматизираме този процес.

ImageMagick е комплект с елементарни инструменти за графична обработка. Могат да конвертират формати, да правят колажи, да кропват, да комбинират снимки, да слагат маски… poor man’s photoshop 🙂 Естествено безплатен е и се ползва през командния ред, което го прави много удобен за скриптове.

Създаваме файла /bin/wmpic.sh със следното съдържание:

#!/bin/bash
filename=`basename "$1" | sed 's/\.\([^\/\.]*$\)//'`
composite -gravity southeast -quality 90 ~/watermark_small.png $1 ${filename}_WM.jpg
echo "Done: ${filename}_WM.jpg"

Няма да обяснявам кое какво прави – имате man страници на bash и на composite 🙂

Резултата е че с един ред правим изображение с воден знак:

$ wmpic.sh IMG_1789_90_91_fused.jpg
Done: IMG_1789_90_91_fused_WM.jpg

scp resume

Wednesday, May 18th, 2011

scp е много удобен инструмент за прехвърляне на файлове между различни машини. Може да работи както за ъплоуд, така за даунлоуд, та даже и директно да мести от втора на трета машина. Използва демона на SSH и не се налага да стартирам допълнителни услуги.

Примерна употреба:

scp -P220 192.168.2.1:/extra/ivanatora/snimki/2011_05_18_plovdiv/ .

Взима рекурсивно папката 2011_05_18_plovdiv/ от домашното ми PC и я копира на текущата машина (лаптопа). Освен това -P опцията ще рече че SSH слуша на порт, различен от дефаултния. Ако искам да направя трансфер в обратната посока само трябва да разменя source и destination.

Та така днес рекох да си олекотя малко харда на лаптопа и да прехвърля всички файлове на таймлапсовете от предните постове на домашното PC. Това са доста файлове – 20 хиляди е добро предположение. Общия размер е към 2-3GB, което не е много и в случая това което натоварва са операциите за отваряне и затваряне на файлове. А да – и имах неблагоразумието да пусна всичко това да върви през един wifi рутер, който забива като се погледне накриво. Всичко си вървя към един-два часа, когато трансфера спря и scp умря с “Connection closed: broken pipe”.
Опцията беше да го пусна на ново, да чакам час-два и пак да забие. scp няма resume. Освен това не копира файловете в някакъв ред, а хаотично. Не мога да видя до къде е стигнало (коя папка от петте, кой пореден файл) и да продължа ръчно от там.

Тук на помощ идва rsync. Какво е и как се ползва – който иска да чете man-страницата.

Това което ми свърши работа – довърши копирането без да презаписва вече качените файлове:

rsync -r –partial –progress timelapse_* –rsh=’ssh -p220′ 192.168.2.1:/extra/ivanatora/snimki/

Аргументите:

  • -r – рекурсивно пълзи по директорията-източниик
  • –partial – запазва файловете, които вече ги има в целта
  • –progress – показва колко файла остават и до къде е стигнало
  • timelapse_* – папките-източник; * се експандва от шела до timelapse_11_04_2011, timelapse_sky_09_04_2011 и т.н.
  • –rsh=’ssh -p220′ – използва алтернативна команда за пренасяне на файловете. Може да е SSH, но има и други варианти
  • 192.168.2.1:/extra/ivanatora/snimki/ – директорията-цел

Автоматично прекратяване на интерактивна sudo сесия

Thursday, April 28th, 2011

Сценарият е следния: Ubuntu машина, стандартен потребител (ivanatora), който има нужда да свърши няколко неща изискващи root достъп. Вместо потребителя да пише sudo преди всяка команда, той си съкращава писането с:

$ sudo -i
[sudo] password for ivanatora: 
# 

И минава в интерактивен root-ски логин. От този логин той излиза с `exit` или CTRL+D. До тук всичко е ясно.

Проблем: root логинът се захвърля на някоя конзола измежду всички останали и се забравя там. На повечето системи, които съм виждал този логин би останал отворен вечно, докато не се затвори ръчно.

Решение: следното се добавя в /root/.profile

if [ $SUDO_USER ]; then
        export TMOUT=1200
fi

Обяснение: Опцията “-i” симулира първоначален логин, като се изпълняват и съответните файлове ~/.profile, ~/.bash_profile и т.н. на новия акаунт. TMOUT е променлива на средата, която казва колко секунди след последния вход ще се прекрати процеса. Ако се сложи TMOUT=0 автоматичното прекратяване ще се забрани. SUDO_USER е променлива на средата показваща кой е потребителят изпълнил sudo. На някои системи тази променлива не съществува и там трябва да се ползва “who am i” (с интервалите).