Hlavní navigace

Hrátky z řádky: find to najde

14. 4. 2008
Doba čtení: 4 minuty

Sdílet

Opět se setkáváme u pravidelné pondělní dávky tipů a triků z černé řádky. Dnes se vracíme k hledání. Celý díl bude věnován příkazu find. Ten je velmi mocný, jak dále uvidíte, umožní nám víc než jen hledání. Find prochází adresářovou strukturu a dokáže nad soubory provádět různé užitečné akce.

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

CS24_early

$ 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.

Byl pro vás článek přínosný?

Autor článku

Petr Macek studoval aplikovanou informatiku na Jihočeské univerzitě, pracuje jako síťový specialista ve firmě Kostax, s. r. o. Baví ho především FreeBSD, sítě a monitoring Cacti.