Unixcyclopedia - find

August 30th, 2007 Alex

find este una dintre cele mai utile comenzi valabile din linia de comandă, fiind unul din cele mai bune argumente împotriva folosirii managerelor de fişiere grafice (gen Windows Explorer). Cu un File Explorer grafic nu poţi spune într-un mod eficient “caută-mi toate imaginile ce au fost modificate de utilizatorul alex săptămâna trecută, fă arhivă cu ele, şi trimite-le pe mail lui gigi@gmail.com”. Combinată cu “xargs”, plus alte utilitare ce operează pe fişiere, astfel de operaţii devin de 10 ori mai uşoare şi mai uşor de automatizat.

Descriere pe scurt: caută fişiere ce corespund criteriilor date.

Problema 1: efectuează o căutare recursivă în directorul curent după numele fişierului (cu wildcards)

find . -name "*.jpg"

Rezultatul este ceva de genul …

...
./Fotografii/Vacanțe/La Mare (2007)/dsc00956.jpg
./Fotografii/Vacanțe/La Mare (2007)/dsc00957.jpg
./Fotografii/Vacanțe/La Mare (2007)/dsc00958.jpg
./Fotografii/Vacanțe/La Mare (2007)/dsc00959.jpg
...

Directorul unde se face căutarea este cel curent, denotat cu “.”, dar se poate specifica un alt director.

Problema 2: caută toate fişierele ce aparţin de un anumit utilizator.

find . -user alex

Iar rezultatul este iarăşi ceva de genul …

...
./Audio/ToConvert/Diverse/05-senses-ube.ogg
./Audio/ToConvert/Diverse/06-empathy-ube.ogg
./Audio/ToConvert/Diverse/07-reality-ube.ogg
./Audio/ToConvert/Diverse/08-sanity-ube.ogg
./Audio/ToConvert/Diverse/09-identity-ube.ogg
...

Problema 3: caută fişierele de un anumit tip

Un director este tot un fişier. Deasemenea, sub Linux/Unix, pe lângă fişierele fizice de pe hard-disk mai există şi alte tipuri de fişiere (sub Unix filozofia este … aproape orice resursă poate fi tratată ca un fişier).

Tipurile de fişiere disponibile, aşa cum apar la listing-ul comenzii “ls”, sunt …

- - fişier normal
d - director
l - link
c - fişier special (în general se găsesc în /dev)
s - socket
p - named pipe

Pentru a căuta doar anumite tipuri de fişiere (cum ar fi directoarele) cu find, putem utiliza ceva de genul:

find ~/Media/Fotografii/ -type d

Iar rezultatul …

...
/home/alex/Media/Fotografii/Evenimente/Pasti (2007)
/home/alex/Media/Fotografii/Evenimente/Nuntă Ștefan & Veronica
/home/alex/Media/Fotografii/Evenimente/Moț Ioana
/home/alex/Media/Fotografii/Evenimente/Revelion 2006
...

Problema 4: caută fişierele ce depăşesc o anumită dimensiune:

find ~/Media/Audio -size +10M

Problema 5: combinarea şi negarea condiţiilor … caută toate fişierele din directorul cu fişiere audio ce depăşesc 1 MB şi nu sunt mp3-uri :)

Argumentele pot fi combinate pentru alcătuirea unor criterii de selecţie mai specializate. Deasemenea condiţiile incluse pot fi negate dacă punem în faţa condiţiei semnul exclamării.

find ~/Media/Audio -size +10M ! -name *.mp3

Autopsii :)

Cu find poţi examina ce fişiere au fost modificate în ultimele 3 zile, sau în ultimele 30 de minute de exemplu. Poţi căuta fişiere cu un anumit set de permisiuni. Poţi deasemenea căuta fişiere ce *nu* aparţin de vreun utilizator sau grup.

Cu astfel de căutări poţi face diagnostice în cazul în care ceva nu merge bine (de exemplu în cazul în care sistemul a fost crăcuit, God forbid).
Aşadar şi prin urmare …

Problema 6: cum pot căuta fişierele ce au modificate/accesate în ultimele X zile ?

Opţiunile disponibile sunt următoarele:

-atime: când au fost fişierele ultima oară accesate
-ctime: când au fost permisiunile fişierelor ultima oară schimbate
-mtime: când au fost fişierele ultima oara schimbate

Parametrul [număr întreg] ce apare lângă aceste opţiuni specifică numărul maxim de zile de la ultima schimbare.

Astfel, pentru a afla fişierele ce au fost schimbate în ultimele 24 de ore:

find /etc -user root -mtime 1

Se pot specifica şi minute în loc de zile, folosind următorul set de instrucţiuni:

-amin: în loc de atime
-cmin: în loc de ctime
-mmin: în loc de mtime

Astfel, pentru a afla fişierele ce au fost schimbate în ultimele 30 de minute:

find /etc -user root -mmin 30

Pentru a afla fişierele ce au fost accesate în ultimele 5 minute:

find /etc -user root -amin 5

Problema 7: cum pot afla toate fişierele cu permisiuni complete de accesare?

find ~ -perm 777

Alte opţiuni utile

-nouser: arată fişierele care nu sunt asociate cu un user
-nogroup: arată fişierele care nu sunt asociate cu un grup
-links n: fişierul are N link-uri
-newer file: se găsesc fişierele modificate mai recent decât fişierul “file”

Combinarea comenzii cu xargs

Este foarte util să combini comanda find cu alte comenzi din consolă pentru a putea executa operaţii complexe pe fişiere. E util de exemplu să iei toate imaginile ce aparţin lui Alex şi au fost modificate azi şi să le muţi într-un director de backup.

Comanda find mai suportă şi opţiunea “-exec” pentru rularea unei comenzi pentru fiecare nume de fişier găsit. Însă eu prefer să mă leg de comanda xargs deoarece combinaţia este mai rapida (-exec rulează o instanţă separată a programului declarat pentru fiecare fişier găsit, şi performanţa e mult mai mică pentru un număr mare de fişiere găsite).

Despre xargs: comanda combină parametrul dat cu liniile venite din stdin şi execută comanda astfel creată.
De exemplu “echo "newDirectory" | xargs mkdir” este echivalent cu “mkdir newDirectory“.

Apare însă o problemă: numele de fişiere pot conţine newlines, iar separarea din output a fişierelor din toate exemple de până acum s-a făcut cu newline (fiecare fişier fiind tipărit pe o linie nouă). Pentru a evita astfel de erori la combinarea cu comanda “xargs” se foloseşte parametrul “-print0″ ce pune caractere NULL ca despărţitor în loc de newline … iar la comanda xargs se foloseşte parametrul “-0″ pentru a indica folosirea caracterelor NULL în stdin. Vezi exemplul următor.

Problema 8: cum pot muta toate imaginile JPG (în afară de cele ce au fost făcute “la mare”) într-un director de backup ?

find ~/Media -name *.jpg ! -iwholename *mare* -print0 | xargs -0 mv --target-directory ~/Backup

În încheiere
Desigur, comanda find este chiar complexă şi mai are parametrii posibili de care n-am discutat, deşi i-am acoperit pe cei mai importanţi. Ca de obicei, de câte ori uiţi un parametru sau vrei sa afli mai multe …

man find

Posted in shell, unix, unixcyclopedia | 4 Comments »

Unixcyclopedia - grep

August 20th, 2007 Alex

Prefaţă

Nu sunt singurul care şi-a dat seama de puterea liniei de comandă. Sunt genul de om minimalist, ce-şi bazează munca pe unelte flexibile şi evit cu dârzenie folosirea mediilor de dezvoltare monolitice :) Filozofia UNIX, unde uneltele fac un lucru, dar îl fac bine, întotdeauna m-a atras. Însă din lipsă de timp nu m-am documentat decât “pe diagonală” cu privire la uneltele din lumea UNIX, şi simt că nu-mi folosesc calculatorul la capacitate maximă.

Incep prin urmare o serie de articole mici, destinate utilizării diverselor utilitare din linia de comandă (şi nu numai) … folositoare în primul rând mie, deoarece în acest fel sunt forţat să mă documentez mult mai riguros. Şi cine ştie, poate nu sunt singurul interesat de astfel de reţete.

GREP

Probabil cel mai folosit utilitar din linia de comanda, grep este folosit pentru a căuta apariţii de texte în fişiere. Pentru filtrarea propriu-zisă se dau drept condiţii expresii regulate a căror sintaxă vine în trei versiuni: basic, extended şi perl … adică toate variantele care contează.

Problema nr 1: Cum caut în toate fişierele din directorul curent apariţia cuvântului “wordName” ?

grep -r wordName .

-r — opţiunea parcurge recursiv directorul indicat (în cazul nostru directorul curent, indicat prin “.” [punct]). Instrucţiunea este echivalentă cu …

find . -print | xargs grep wordName

Problema nr 2: Cum fac o căutare case-insensitive în toate fişierele cu extensia “*.rb” din directorul /home/alex/sampleDir ?

grep -i -r --include=*.rb wordName /home/alex/sampleDir

Opţiunea -i este pentru căutare case-insensitive. Iar opţiunea –include face căutarea doar în fişiere ce se potrivesc şablonului indicat.

Instrucţiunea este echivalentă cu …

find /home/alex/sampleDir -name *.rb -print | xargs grep wordName

Problema nr 3: cum fac să-mi afişeze contextul rezultatelor găsite la căutare ?

grep -C 1 alex /etc/passwd

Cu opţiunea -C [n] se afişează n linii de deasupra şi n linii de dedesuptul liniei ce corespunde căutării.

Problema nr 4: cum fac să-mi afişeze doar calea către fişierele ce sunt găsite la căutare ?

grep -l 'class' *.php

Comanda de mai sus poate fi combinată pentru efecte super-marfă. De exemplu putem copia toate fisierele *.php ce conţin cuvântul “class” într-un director la alegere …

grep -l 'class' *.php | xargs mv -t /target/directory

Problema nr 5: cum pot afla PID-ul proceselor Apache ?

Oops, o problemă practică şi extrem de uzuală ?

Pentru o afişare brută, este suficient ceva de genul …

ps aux | grep [a]pache

“ps” afişează lista de procese active, dar ce-i cu expresia “[a]pache” ? Simplu … dacă puneam cuvântul “apache” s-ar fi afişat în listă şi procesul comenzii enunţate.

Pentru omorârea tuturor proceselor “apache” (presupunând că s-au blocat şi nu e posibilă oprirea normală … situaţie destul de anormală) e suficientă o comandă de genul …

ps aux | grep [a]pache | awk ‘{print $1}’ | xargs kill -9

Eh … “awk” este un zeu al procesării de texte, dar vorbim altădată despre asta :)

Problema nr 6: cum pot elimina liniile nedorite (cum ar fi liniile goale) dintr-un fişier ?

cat file.txt | grep -v ^[[:space:]]*$

Opţiunea -v afişează toate liniile care nu corespund expresiei date.

Problema nr 7: cum pot afişa numele tuturor fisierelor care nu conţin un anumit cuvânt ?

Să zicem că vrem să aflăm toate fişierele *.php din directorul curent care nu conţin cuvântul “function”.

grep -L 'function' *.php

Opţiunea -L afişează toate fişierele unde nu este găsită nici o linie ce corespunde expresiei.

Concluzie

grep este o comandă pe cât de simplă, pe atât de puternică. Aş vrea să dau un ultim exemplu ce demonstrează capabilitaţile de combinare a comenzilor prin pipe-urile liniei de comandă:

ps aux | grep [a]pache | grep root | awk ‘{print “/proc/” $2 “/status”}’ | xargs cat | grep -i vm

Comanda (testată pe Debian/Ubuntu) afişează ceva e genul …

VmPeak: 23252 kB
VmSize: 23252 kB
VmLck: 0 kB
VmHWM: 6716 kB
VmRSS: 6716 kB
VmData: 3068 kB
VmStk: 88 kB
VmExe: 328 kB
VmLib: 18528 kB
VmPTE: 32 kB

Pretty cool, huh ?

Cu puţină imaginaţie e posibilă crearea unor instrumente de monitorizare a proceselor destul de avansate ;)

Posted in shell, unix, unixcyclopedia | 3 Comments »