Inotify
Inotify není žádná novinka, v hlavní větvi Linuxu je od verze 2.6.13, která vyšla v roce 2005 a nahradil starší a hloupější systém dnotify. Inotify nabízí jednoduché API, jehož prostřednictvím můžete zacílit na konkrétní adresáře, nebo přímo soubory (je založený na inodech, od toho to I na začátku) a dostávat informace o událostech, které se v nich dějí. Na základě událostí pak můžete spouštět vlastní aktivity, které budou události zpracovávat. Místo toho abyste v nějakém časovém intervalu kontrolovali soubor, nebo adresář a dívali se, zda se něco nezměnilo (tzv. polling), budete v klidu čekat na zprávu přímo od vykonavatele těch změn, který umí být o poznání efektivnější.Inotify má ale jistá omezení, funguje pouze na lokálních filesystémech a neumí rekurzivně sledovat podadresáře, to už si musí klienti zajistit sami, rozšířením objednávky. Kapacita není neomezená, maximum sledovaných inodů je
/proc/sys/fs/inotify/max_user_instances - pro maximální počet objektů využívajících současně inotify
/proc/sys/fs/inotify/max_user_watches - pro maximální počet sledovaných inodů
Všechny běžné programovací jazyky mají k dispozici patřičnou knihovnu pro využití Inotify (cé žádnou samozřejmě nepotřebuje), ale jsou k mání i efektivní nástroje pro využití z konzole a tím se budu zabývat v tomto příspěvku.
Inotify z konzole
Základními konzolovými nástroji jsou utility inotifywatch a inotifywait, které nainstalujete takto:
sudo apt-get install inotify-tools
Zatímco inotifywatch umí sbírat statistiky, inotifywait je akčnější nástroj, který umí čekat na určitou událost, po které vyplivne požadovaná data a skončí, čímž může fungovat jako spoušť pro další příkazy, které jeho data mohou zpracovat. Umí ale fungovat i jako monitor. Pokud budete chtít v reálném čase sledovat dění v konkrétním adresáři, můžete na to jít takto:
inotifywait -qm /cesta/k/adreasáři/nebo/souboru
Přepínač -q zajistí, že inotifywait nebude pindat zbytečně a -m je pro monitor, nedojde tedy po první události k ukončení, ale pokračuje se dál.
Můžete čekat i na konkrétní událost, třeba vytvoření souboru v konkrétním adresáři a následně vypsat celou cestu k němu:
inotifywait -qe create --format %w%f /cesta/k/adresáři/
Přepínačem -e určujete jaké události vás zajímají. Přepínač --format umí formátovat výstup podobně jako printf, v tomto případě udává %w cestu k monitorovanému objektu a %f jeho jméno. Událost create nastane i při přepisu souboru tím samým, v tomto případě se ale nedočkáte jména souboru, ale kódu začínajícího .goutputstream-. Pokud byste chtěli rekurzivně hlídat i všechny podadresáře, můžete použít přepínač -r.
Příklad - Akční adresář pdf-to-png - 1
Zkusím reálné použití demonstrovat na příkladu, který jsem zmínil v úvodu. Pro převod pdf do png použiju utilitu convert z balíku imagemagick, který nainstalujete příkazem:
sudo apt-get install imagemagick
Vlastní skript pak může vypadat takto:
pdf-to-png-1.sh
#!/bin/bash
dir="$HOME/pdf-to-png/"
inotifywait -qm -e close_write --format %w%f "$dir" | while read file
do
[[ "$file" =~ \.pdf$ ]] && convert -density 150 "$file" "$file.png" && rm "$file"
done
dir="$HOME/pdf-to-png/"
inotifywait -qm -e close_write --format %w%f "$dir" | while read file
do
[[ "$file" =~ \.pdf$ ]] && convert -density 150 "$file" "$file.png" && rm "$file"
done
Dokud skript běží, inotifywait v režimu monitorování (přepínač -m) vypisuje cesty k souborům které vyvolaly událost close_write týkající se zavření souboru otevřeného pro zápis v adresáři ~/pdf-to-png. Cesty putují rourou do smyčky, která jednu po druhé zpracovává - vybírá jen soubory s koncovkou .pdf, ty převádí pomocí utility convert na sérii png obrázků a poté původní pdf smaže. Přepínač -density určuje hustotu výsledného obrázku - čím vyšší, tím bude mít obrázek vyšší rozlišení.
Všiměte si, že událost close_write nastane třeba vytvořením nového souboru, ale pokud soubor do sledovaného adresáře pouze přesunete v rámci stejného filesystému, nebude skript reagovat, protože tato akce vyvolá událost moved_to, kterou nepokrývá. To funguje i jako ochrana před nechtěným smazáním původního pdf, když ho místo zkopírování jen přesunete, nic se mu nestane. Pokud by měl skript zpracovávat i přesunuté soubory, museli byste použít ještě jeden přepínač -e s parametrem moved_to. Událost create jsem nepoužil proto, že je generována ještě předtím, než se zapíší všechna data a to může logicky způsobit problém.
Jinak skript berte čistě ilustračně, podmínka pro detekci přípony je dost omezená a pro nějaké nasazení by to bylo potřeba trochu ošetřit výjimky, atd...
Události, které můžete sledovat (pokud jich potřebujete sledovat více, použijete přepínač -e násobně, pro každý typ události zvlášť):
- access Ze sledovaného souboru, nebo souboru ve sledovaném adresáři bylo čteno.
- modify Sledovaný soubor, nebo soubor ve sledovaném adresáři byl změněn, bylo do něj zapsáno.
- attrib Byla změněna metadata sledovaného souboru, nebo souboru ve sledovaném adresáři. To zahrnuje oprávnění, časové údaje a další atributy.
- close_write Sledovaný soubor, nebo soubor ve sledovaném adresáři byl zavřen po předchozím otevření v režimu zápisu. To nutně neznamená, že do něj bylo zapsáno.
- close_nowrite Sledovaný soubor, nebo soubor ve sledovaném adresáři byl zavřen po předchozím otevření jen pro čtení.
- close Sledovaný soubor, nebo soubor ve sledovaném adresáři byl zavřen., bez ohledu na to, v jakém režimu byl otevřen. Ve skutečnosti tato událost zahrnuje obě předchzí a tak výsledná událost bude vždy close_write, nebo close_nowrite, nikoliv close.
- open Sledovaný soubor, nebo soubor ve sledovaném adresáři byl otevřen
- moved_to Do sledovaného adresáře byl přesunut soubor, nebo adresář. Tato událost nastane i tehdy, když je výchozí adresář ten samý, jako cílový.
- moved_from Ze sledovaného adresáře byl přesunut soubor, nebo adresář. Tato událost nastane i tehdy, když je výchozí adresář ten samý, jako cílový.
- move Zahrnuje události moved_to a moved_from, událostí tedy ve skutečnosti není move, ale jedna z jmenovaných.
- move_self Sledovaný soubor, nebo adresář byl přesunut. Po této události sledování končí.
- create Ve sledovaném adresáři byl vytvořen nový soubor.
- delete Ve sledovaném adresáři byl smazán soubor.
- delete_self Sledovaný soubor, nebo adresář byl smazán. Po této události sledování samozřejmě končí.
- unmount Souborový systém, na kterém se nacházel sledovaný soubor, nebo adresář byl odpojen. Po této události sledování samozřejmě končí také.
Incron
Incron je na Inotify založená služba odvozená od klasického cronu s tím rozdílem, že se neřídí časovým rozvrhem, ale událostmi ve sledovaném adresáři. Skládá se z démona incrond a nástroje pro správu pravidel incrontab. Pro inspiraci, přímo autor Lukáš Jelínek uvádí následující možnosti využití jeho díla a vlastně obecně systému Inotify:- hlídání změn v konfiguraci a automatická notifikace programů
- hlídání kritických souborů před změnou
- monitoring použití souborů, statistika
- automatický úklid po spadlých programech
- automatické zálohování souborů při změně
- notifikace při příchodu pošty
- notifikace při uploadu souborů na server
- monitoring instalací nestandardním způsobem (mimo balíčkovací systém)
- ...a mnoho dalšího
Instalace:
sudo apt-get install incron
Služba se po instalaci v Ubuntu automaticky spustí a bude se spouštět i po restartu systému.
Po instalaci nemá žádný uživatel, včetně roota, právo incron používat, nejprve je potřeba uživatele, kteří oprávnění mít mají, přidat do souboru /etc/incron.allow. Další možností je tento soubor smazat, pak mohou incron používat všichni lokální uživatelé.
Pro editaci pravidel incronu pro aktuálního uživatele se používá příkaz
incrontab -e
Stejně jako u cronu, i zde si při prvním spuštění vyberete váš oblíbený editor a pak už můžete vesele zapsat svá pravidla. Jednotlivá pravidla se tvoří takto:
<cesta> <maska> <příkaz>
Jako masku můžete použít jednu, nebo více z následujících událostí (oddělují se čárkami):
- IN_ACCESS Přístup k souboru - čtení
- IN_ATTRIB Změna metadat (práva, časové údaje, atd.)
- IN_CLOSE_WRITE Soubor otevřený pro zápis byl zavřen
- IN_CLOSE_NOWRITE Soubor otevřený pouze pro čtení byl zavřen
- IN_CREATE Soubor/adresář byl vytvořen
- IN_DELETE Soubor/adresář byl smazán
- IN_DELETE_SELF Byl smazán přímo sledovaný adresář
- IN_MODIFY Soubor byl změněn
- IN_MOVE_SELF Sledovaný adresář byl přesunut
- IN_MOVED_FROM Soubor byl přesunut z adresáře
- IN_MOVED_TO Soubor byl přesunut do adresáře
- IN_OPEN Soubor byl otevřen
Proměnné, které v zápisu pravidel incrontabu můžete použít jako argumenty pro vaše skripty:
- $$ - znak $
- $@ - cesta ke sledovanému adresáři. Zde pozor, je to řetězec, který jste zadali do vašeho pravidla vy a pokud budete chtít jednoduše spojit tuto proměnnou s tou následující (↓), dáte na konec cesty i lomítko
- $# - jméno souboru, kterého se událost týká
- $% - typ události textově
- $& - typ události numericky
Příklad - Akční adresář pdf-to-png - 2
Pravidlo pro výše zmíněný příklad s rozkladem pdf souborů může vypadat takto:
$HOME/pdf-to-png/ IN_CLOSE_WRITE /cesta/k/pdf-to-png-2.sh $@$#
Vlastní skript:
pdf-to-png-2.sh
#!/bin/bash
if grep -iqE '\.pdf$' <<< $@
then nice convert -density 150 "$@" "$@.png" && rm "$@"
fi
if grep -iqE '\.pdf$' <<< $@
then nice convert -density 150 "$@" "$@.png" && rm "$@"
fi
Schválně jsem použil jinou podmínku, než minule, tahle je lepší, univerzálnější. Také jsem přidal příkaz nice, který zajistí, aby proces konverze měl nižší prioritu, než běžné procesy a tak když bude CPU potřeba pro důležitější záležitosti, nebude ostatní blokovat.
Závěrem
Vytvořit si třeba na pracovní ploše speciální adresáře, které by automaticky zpracovávaly vložené soubory různými způsoby, to je lákavá záležitost. Takový adresář nemusí být jednoúčelový, může podle koncovek souborů rozhodovat, co se souborem provede. Pomocí systémových notifikací se mužete nechat informovat o změnách v důležitých souborech, zkrátka spousta zábavy a v neposlední řadě i užitku :)V repozitářích je ještě pár dalších aplikací založených na Inotify, můžete se podívat třeba příkazem
apt-cache search inotify
Odkazy k tématu:
http://www.kernel.org/doc/man-pages/online/pages/man7/inotify.7.htmlhttp://inotify.aiken.cz/
http://www.ibm.com/developerworks/linux/library/l-ubuntu-inotify/
Jejda, tak tohle je pěkný povídání, po všech těch kravinách ;-)
OdpovědětVymazatKonečně jsem našel alternativu k Macovskému automatoru :o)
OdpovědětVymazatMám ale jeden problém pramenící čistě z neznalosti. Rád bych si udělal skript pro akci složky, která bude konvertit obrázky. Chápu, že [[ $file... definuje proměnnou s názvem souboru, když ale udělám [[ $file =~ \.jpg$ ]], soubor to prostě ve složce nenajde, v tom zápisu bude nějaká bota, ne?
Díky
Ten test není napsán příliš univerzálně, rozhodně bere jen přípony s malými písmeny, ale jinak funguje. =~ znamená 'obsahuje' daný řetězec a $ určuje, že musí být na konci řetězce. Jinak by se to dalo napsat lépe třeba takto:
Vymazatif grep -iq '.jpg$' <<< $file; then ...; else ...; fi
Pak ještě pro jistotu dodám - ten skript musí běžet, jedině tak si může všimnout, že se do adresáře něco zapisuje. Nefunguje to na soubory, které již v adresáři jsou.
Pro nějaké trvalejší používání by bylo vhodné to napsat lépe celé a ošetřit případné chyby při zpracování, aby se to při prnví příležitosti nerozpadlo..
A pravda [[ $file... mělo být [[ "$file"..., jinak to s názvy s mezerami bude nefunkční
Vymazat