Linux v příkazech - hledání souborů

Ke správě souborů nevyhnutelně patří i jejich hledání. Naučení se několika trikům může v budoucnu ušetřit spoustu času.

29.5.2006 06:00 | Jiří Václavík | přečteno 102235×

Hledání souborů patří mezi relativně častou činnost. Téměř veškeré hledání se v Linuxu provádí příkazy find a locate.

Příkaz find - univerzální nástroj na hledání souborů

find prochází adresářovou strukturou od zadané úrovně a s každým vyhovujícím souborem provádí definovanou akci. Vyhovující je soubor tehdy, splňuje-li všechny zadané podmínky.

Zaměřme se nyní na syntaxi příkazu. Ta obecně vypadá následovně.

$ find [přepínače] [cesty] [výraz]

Jak find prochází adresářovou strukturu, jsou soubory postupně zpracovávány pomocí výrazů. Výrazy určují podmínky pro vyhovující soubory i samotné akce. Právě jimi se bude zabývat značná část tohoto článku.

Výraz začíná na jeden ze znaků !-(,).

Není-li uveden žádný výraz, je význam stejný, jako by zde byl výraz -print, který tiskne jména souborů na standardní výstup. Pomocí -print můžeme vypsat vyhovující jména souborů v určitém adresáři.

Pokud není uvedena cesta, prohledává se aktuální adresář.

Konkrétnější příklad hledá v zadaném adresáři hledaný soubor a výsledky vypisuje.

$ find /zadany/adresar -name hledany_soubor -print

A následující příkaz vypisuje rekurzivně seznam všech souborů aktuálního adresáře.

$ find

Nutno poznamenat, že pro hledání souborů pouze podle názvu je často lepší použít příkaz locate, jež je k tomuto účelu přímo určený.

Výrazy

Výrazy se skládají z operandů a operátorů. Nyní si nejužívanější zástupce z nich představíme. Protože příkaz find má složitější syntaxi, uvedeme si k nim také větší množství příkladů.

Operátory

Jednotlivé operandy jsou odděleny operátory. Následující tabulka operátorů je seřazena podle priority od nejvyšší k nejnižší.

OperátorVýznam
( výraz )závorky
! výraz, -not výraznegace
výraz výraz, výraz -a výraz, výraz -and výrazlogické A
výraz -o výraz, výraz -or výrazlogické NEBO
výraz , výrazvyhodnotí se oba výrazy, ale použije se jen návratová hodnota druhého

Operandy

Operandy tvoří výrazy pro operátory. Můžeme je rozdělit na tři skupiny.

Skupina operandůVýznamNávratová hodnota
volbyupřesňují chování příkazutrue
testytestují soubortrue nebo false
akceprovádí nad soubory danou činnosttrue nebo false
Volby

Volby upravují činnost příkazu a vždy vracejí pravdivou hodnotu.

VolbaVýznam
-daystartčas se počítá od 0:00, nikoliv od okamžiku před 24 hodinami, jak je tomu implicitně
-maxdepth nnastavuje největší hloubku zanoření do podadresářů
-mindepth nnastavuje nejmenší hloubku zanoření do podadresářů (nejsou tedy zpracovávány soubory zanořené níže, než je uvedeno)
-follownásleduje symbolické odkazy
-xdevneprocházejí se adresáře na jiných souborových systémech
-depthpřednost při zpracování má obsah adresáře před ním samotným

Pro výpis všech souborů v aktuálním adresáři bez rekurze nastavíme úroveň zanoření na 1.

$ find . -maxdepth 1
Testy

Testy jsou hlavní složkou výrazů, která se stará o filtrování souborů. Soubory, jež projdou testy, jsou dále obvykle předávány akcím.

Část testů přijímá číselnou hodnotu. Čísla lze většinou psát trojím způsobem.

Pro lepší představu si ukažme konkrétní příklad. Hledáme-li soubor, který byl naposledy otevřen před 4 dny, zadáme -atime 4. Hledáme-li soubor, který byl naposledy otevřen později, než před 4 dny (před 3, 2 nebo 1 dnem), použijeme volbu -atime -4. Poslední možností je soubor otevřen před více než 4 dny (před 5, 6, 7 nebo více dny) - tedy -atime +4.

Zde je přehled testů příkazu find.

TestVýznam
-truepravda
-falsenepravda
-name souborsoubor má daný název, přičemž lze zadávat žolíkové znaky
-lname souborobsah symbolického odkazu odpovídá zadanému jménu, lze opět použít žolíkové znaky
-amin nsoubor byl otevřen před n minutami.
-atime nsoubor byl otevřen před n dny.
-anewer souborsoubor byl otevřen dříve než uvedený soubor
-cmin ni-uzel souboru byl změněn před n minutami.
-ctime ni-uzel souboru byl změněn před n dny.
-cnewer soubori-uzel souboru byl změněn dříve než uvedený soubor
-mmin nsoubor byl změněn před n minutami.
-mtime nsoubor byl změněn před n dny.
-newer souborsoubor byl změněn dříve než uvedený soubor
-emptysoubor (platí i pro adresář) je prázdný
-perm právasoubor má nastavena daná přístupová práva
-uid uidsoubor má uid
-gid gidsoubor má gid
-group skupinasoubor patří skupině
-user uživatelsoubor patří uživateli
-regex vzorjméno souboru s cestou vyhovuje vzoru
-type typtestuje soubor na zadaný typ (viz dále)
-size n[jednotka]soubor má danou velikost (viz dále)
-samefile souborsoubor má tentýž i-uzel jako uvedený soubor

Argument testu -type může být jedním z následujích znaků.

Jednotka u testu -size může nabývat hodnot b (jednotkou jsou 512 B bloky), w (dvoubajtová slova), c (B), k (KiB), M (MiB) nebo G (GiB).

U testů implicitně záleží na velikosti písma. Chceme-li vyhledávat názvy s libovolnou velikostí, existují pro testy, pro něž to má smysl, i varianty na velikosti nezávislé. Začínají vždy písmenem i. Lze použít testy -iname, -ipath, -iregex a -ilname.

Pro nalezení všech souborů aktuálního adresáře, které obsahují kdekoliv ve svém názvu řetězec 2006, použijeme následující příkaz.

$ find . -name '*2006*'

Chceme-li najít ve svém domovském adresáři všechny dokumenty formátu Open Document (předpokládáme, že mají vždy příponu .odf), zadáme

$ find ~ -name '*.odf'

Dále najdeme soubory v adresáři /data/2006, které byly modifikovány během posledních tří minut. Protože je to interval končící v okamžiku zadání příkazu, zadáme záporné číslo. Pokud bychom předali číslo bez znaménka, získali bychom soubory modifikované přesně před třemi minutami.

$ find /data/2006/ -mmin -3

Nyní budeme naopak hledat soubory, k nimž není zaznamenán přístup již déle než rok.

$ find ~ -atime +365 -print

Najdeme všechny soubory v aktuálním adresáři o velikosti mezi 200 a 300 KiB. Pozor však na případy, kdy má soubor alokováno více místa než skutečně používá. Pro zjištění velikosti souboru použijeme příkaz du.

$ find . -size +200k -size -300k

Najdeme rekurzivně všechny soubory v adresáři /home, jejichž vlastníkem je uživatel uzivatel.

$ find /home -user uzivatel

A nyní uděláme to samé, ale nebudeme hledat rekurzivně. Budeme hledat pouze v adresáři /home, ale už ne v jeho podadresářích. Nastavíme hloubku zanoření na 1.

$ find /home -maxdepth 1 -user uzivatel

Najdeme všechny soubory, jejichž práva mají hodnotu 700.

$ find . -perm 700

Znaménka + a - zde fungují jako operátory A a NEBO. Nyní najdeme ty soubory, které může vlastník číst, spouštět nebo do nich zapisovat.

$ find . -perm +700

A teď ty, které splňují všechny uvedené podmínky.

$ find . -perm -700
Akce
AkceVýznam
-printtiskne jména vyhovujících souborů, tato akce je nastavená implicitně
-fprint soubortiskne jména vyhovujících souborů do souboru
-printf formátformátování výstupu
-fprintf soubor formátstejné jako -printf, ale přesměruje výstup do souboru
-exec příkazprovede příkaz, přičemž {} se expanduje do názvu zpracovávaného souboru
-ok příkazstejně jako -exec, ale vyžádá si potvrzení akce
-lsvýpis informací o souboru
-print0tiskne jména souborů oddělená znakem NUL, což je výhodné v kombinaci s příkazem xargs -0
-quitkonec vykonávání príkazu

Pro podrobný výpis všech souborů, které příkaz find najde, použijeme pomocí volby -exec příkaz ls -l. Každý příkaz musíme ukončit středníkem.

$ find -name '*.odf' -exec /bin/ls -l {} \;

Pro smazání všech souborů v adresáři /tmp, které jsou starší než 30 dní, zadáme následující příkaz. Pokud bychom tento příkaz náhodou chtěli provádět periodicky, použijeme cron.

$ find /tmp/ -atime +30 -exec rm -f {} \;

Pro smazání pouze prázdných souborů v aktuálním adresáři použijeme tento příkaz.

$ find . -empty -type f -exec rm -f {} \;

Dále si necháme určit formát souboru pro každý soubor v zadaném adresáři.

$ find . -type f -exec file '{}' \;

Formátování výstupu

Pomocí akce -printf lze tisknout na výstup řetězec přesně podle zadaných kritérií. Struktura takového příkaz find pak vypadá následovně.

$ find [...] -printf 'formátovací řetězec'

Ve formátovacím řetězci lze kromě obvyklých escape sekvencí použít také zástupné symboly začínající znakem procenta. Některé z nich jsou uvedeny v tabulce, kompletní seznam pak je v manuálové stránce.

SymbolVýznam
%%znak %
%Aznak, %ačas posledního přístupu
%Cznak, %cčas poslední změny i-uzlu
%Tznak, %tčas poslední modifikace
%dhloubka zanoření v adresářové struktuře
%Ppouze jméno souboru
%pjméno souboru relativně
%fjméno souboru bez podadresářů
%hcesta k souboru
%g, %Gjméno, číslo skupiny
%u, %Ujméno, číslo uživatele
%mpráva osmičkově
%Hten argument příkazového řádku, díky kterému byl soubor nalezen
%ičíslo i-uzlu
%npočet odkazů
%svelikost v bajtech

Znakem u symbolů %A, %C a %T může být jedna z následujících možností.

ZnakVýznam
lokalizovaný čas
cdatum a čas
Xčas
b, Bdatum
a, Aden v týdnu pevné, volné délky
b, Bměsíc v roce pevné, volné délky
obecný čas
rčas 12 hh:mm:ss
Tčas 24 hh:mm:ss
@počet sekund od 1.1.1970 0:00 GMT
H, I, k, lhodina 00-23, 01-12, 0-23, 1-12
Mminuta 00-59
Ssekunda 00-59
pAM/PM
wden v týdnu 0-6
mměsíc v roce 0-12
jden v roce 001-366
y, Yrok yy, YYYY
Wtýden pondělí-neděle 00-53

Po spuštění následujícího příkazu se zobrazí jména a čas poslední modifikace souboru podle dané šablony.

$ find . -printf 'Soubor %f naposledy změněn v %Ac\n'

Výstup lze formátovat stejně jako céčkovskou funkci printf(3), takže pro přehledný výstup ve sloupcích je možný například tento zápis.

$ find . -printf '%-20f %u (%g)\n'

A nakonec, pro naformátování všech souborů aktuálního adresáře (ty, které zastupuje hvězdička) jako SQL příkazu, zadáme toto.

$ find * -prune -printf "INSERT INTO soubory (jmeno, podadresar, velikost) VALUES ('%f', '%h', %s);\n"

Příkaz xargs

Příkaz xargs provádí akci nad soubory, jejichž jména jsou této funkci předána rourou jako parametry. Perfektně se doplňuje s příkazem find.

xargs je užitečný například tehdy, nestačí-li nám délka řádku shellu.

Typickým příkladem užití příkazu xargs je hledání všech souborů vyhovujících vzoru, které navíc obsahují dané slovo. Následující příkaz najde v adresáři /etc všechny .conf soubory, v nichž se vyskytuje slovo cgi.

$ find /etc -name '*.conf' | xargs grep -li cgi

Poznámka - Teoreticky by mohl fungovat i tento příkaz, avšak selhal by při překročení maximální dělky příkazu v shellu.

$ grep -li cgi `find /etc -name '*.conf'`

Zpracováváme-li soubory s nestandardními jmény, jistě přijde vhod přepínač -0. Ten totiž čte argumenty, jež nejsou odděleny bílým místem, ale znakem NUL. V této souvislosti si vzpomeňme na akci -print0 příkazu find. Tato akce vytváří vstup formátovaný právě pro xargs -0.

Pokud tedy xargs používáme ve spolupráci s find, vždy bychom měli oddělovat argumenty znakem NUL, abychom se vyhnuli případným nepříjemnostem. Poslední příkaz na základě této myšlenky přepíšeme.

$ find /etc -name '*.conf' -print0 | xargs -0 grep -li cgi

A nakonec napíšeme příkaz, který v aktuálním adresáři smaže soubory končící příponou .backup.

$ find . -name '*.backup' -print0 | xargs -0 /bin/rm -f

Rychlé hledání souboru

Příkaz locate hledá zadaný vzor v databázi jmen souborů. Právě díky databázi je výrazně rychlejší než find. Nevýhodou je, že databáze nemusí být vždy aktuální a je třeba ji pravidelně obnovovat.

Pokud zadáme příkaz locate se vzorem jako jediným argumentem, potom budou na výstup vypsány všechny soubory, jež obsahují tento vzor.

$ locate vzor

Mezi přepínače, které lze u příkazu locate použít patří tyto.

PřepínačVýznam
-d databázepoužije se uvedená databáze namísto implicitní
-iignoruje velikost písmen
-cvypisuje pouze počet výsledků
-Svypisuje statistiky
-r, --regexvzor se vyhodnocuje jako regulární výraz

Implicitně databázi máte pravděpodobně v /var/lib/locatedb nebo /var/spool/locate/locatedb. Pokud ani na jednom z těchto umístění není, můžete ji najít pomocí locate.

Databáze se obnovuje příkazem updatedb bez nebo s argumenty. Pomocí voleb --localpaths a --netpaths lze uvést konkrétní cesty, jež se mají prohledávat. --prunepaths naopak konkrétní cesty vynechává, což lze použít například na dočasně připojené oddíly. Argumentem pro tyto volby je řetězec 'cesta1 cesta2 ...'. Pro výstup do konkrétní databáze použijeme --output.

Mimoto by nás možná mohl zajímat program rlocate, který zajišťuje, že je databáze jmen souborů aktualizována automaticky při změnách.

Hledání otevřeného souboru

Nástroje lsof a fuser hledají právě otevřené soubory. Zejména lsof má velké množství všemožných podmínek. Všechny otevřené soubory zjistíme příkazem

$ lsof

Nyní najdeme pouze ty otevřené soubory, které používá aplikace s PID 5687.

$ lsof -p 5687

Pro podrobnější informace o lsof lze nahlédnout do jednoho ze článků uvedených níže.

Další zdroje

Online verze článku: http://www.linuxsoft.cz/article.php?id_article=1225