Find má mnoho parametrů. Zpočátku se vám bude zdát, že zápis moc nedává smysl a že si ho nikdy nezapamatujete. Naštěstí proto tu máme manuálovou stránku.
Struktura příkazu vypadá následovně:
find cesta výraz
Cesta je jasná – od tohoto adresáře níže se bude hledat. U některých verzí find můžeme cestu vynechat a použije se aktuální. U výrazu je to složitější. Sem spadají volby, které obecně ovlivňují hledání, pomocí nich například můžeme říct jen od/do které úrovně (mindepth, maxdepth) hledat, zda procházet symbolické odkazy (follow), … Dále zde máme testy – ty už se týkají hledaných objektů. Z často používaných je to např. typ (adresář, soubor, link, …), vlastník (user, group). Další důležitou možností jsou tzv. akce (exec, ok). Ty nám umožní spustit libovolný příkaz systému a jako parametr mu předat nalezený soubor. Nakonec tu máme operátory sloužící ke skládání výrazů. Jak každá část výrazu vrací hodnoty a jak probíhá vlastní zpracování je pěkně popsané v Linux – dokumentační projekt, kapitola 11. Tam odkazuji zvídavé čtenáře. My se zaměříme na praktické ukázky.
Úplný základ – hledá soubor s názvem soubor.txt v aktuálním adresáři a podadresářích:
$ find . -name soubor.txt
Vyhledá na disku všechny adresáře s názvem pokus (můžeme použít např. -type f
pro soubory, -type l
pro linky):
$ find / -type d -name pokus
Můžeme použít i zástupného znaku ? a *. Budeme hledat v domovském adresáři soubory s příponou txt, začínající postup_ (postup1.txt, postup_aaa.txt, …). Musíme zápis ošetřit, aby nebyl interpretován shellem:
$ find ~ -name postup_\*.txt
nebo
$ find ~ -name "postup_*.txt"
Pokud chceme vyhledat v aktuálním adresáři podadresáře a ty už dál rekurzivně neprocházet:
$ find . -type d -maxdepth 1
Je možné třeba i negovat podmínku, v domovském adresáři hledáme všechny soubory, co nemají příponu txt:
$ find ~ -type f \! -name \*.txt
Zajímavé je i hledání podle časů a velikostí souborů. To co napíšu teď se může trochu lišit v různých verzích findu, proto si pročtěte manuál.
Tento příklad najde v domovském adresáři vše co bylo modifikováno v posledních sedmi dnech:
$ find ~ -mtime -7d
Vše co bylo změněno před více než sedmi dny:
$ find ~ -mtime +7d
Přesně před sedmi dny:
$ find ~ -mtime 7d
Je možné použít písmenka s, m, h, d, w pro vteřiny, minuty, hodiny, dny a týdny. Stejně se dá hledat i podle velikostí, na to je parametr -size. -size +100k
znamená větší než 100 kilobajtů, -100k
menší než 100 kilobajtů a -size 100k
je rovno. Pokud nezadáme k, bude výchozí hodnotou 512 bajtový blok. Pokud chceme podle bajtů, přidejte za číslo písmenko b
.
Vyhledá nám v aktuálním adresáři všechny soubory, které byly změněny dřív než soubor:
$ find . -newer soubor
Tento zápis už tak jednoduše nevypadá, přidáme navíc akci exec. Prázdné složené závorky ( {}
) budou nahrazeny cestou k nalezenému souboru. Vykoná se příkaz ls -al
s touto cestou. Zpětné lomítko před středníkem je důležité. Tím findu říkáme, kde končí příkaz, který chceme vykonávat. Ale středník je i znak, kterým se běžně oddělují příkazy. Při spuštění by se středník chápal jako oddělovač příkazů. Proto jej musíme ošetřit znakem \
nebo zapsat jako ";"
. Příklad najde v akt. adresáři a podadresářích všechny soubory a vypíše o nich detaily:
$ find . -type f -exec ls -al {} \;
Předchozí příklad nám ukazuje sílu findu. Toto nám smaže všechny soubory s příponou .old v současném adresáři a všech podadresářích:
$ find . -type f -name \*.old -exec rm {} \;
Pomocí findu můžete dělat i poměrně velké zásahy, takhle například změníte vlastnictví souborů jednoho uživatele na druhého:
$ find . -user user1 -exec chown user2 {} \;
Pokud si u -exec
nejste jistí, že chcete třeba smazat vše co nám find našel, místo -exec
použijte -ok
. Před každým vykonáním se find zeptá, jestli akci opravdu provést.
Find má mnohem více možností, projděte si manuál, na různých webech věnujících se find najdete spoustu ukázek a praktických příkladů.
Někdy se můžeme setkat s využitím programu xargs
. Ten čte v našem případě ze standardního vstupu jména souborů a vykonává nad nimi zadanou akci (v našem případě mazání):
$ find / -name "*.bak" | xargs /bin/rm -f
nebo
$ find / -name "*.bak" -print0 | xargs -0 /bin/rm -f
Vykonají stejnou funkci jako
$ find / -name "*.bak" -exec rm -f {} \;
V prvním příkladu chápe xargs jako oddělovače mezery a znak nového řádku, a to může být problém, např. když v názvu souboru bude mezera. V druhém případě oddělujeme jednotlivé soubory znakem NULL a mezera nás nemůže zaskočit. V případě bez xargs se rm spustí pro každý nalezený soubor, v tu chvíli find čeká na výsledek mazání. Když použijeme xargs, nalezené soubory určené k mazání se předávají xargs a ten po dosažení limitu (5000, ale můžete jej i změnit) spustí jedenkrát rm ( rm -f soubor1 soubor2 ...
). Výsledek je potom o dost rychlejší. Ke xargs se ještě určitě vrátíme v dalších dílech.