9. Keresés a fájlrendszerben

A fájlrendszerben történő keresést az egyes operációs rendszerek fontos kérdésként kezelik. A Unixok általában több parancsot is kínálnak erre a feladtara, amelyek működési módja és szolgáltatási köre is más és más.

9.1. A find

A find parancs fájlok, könyvtárak stb. keresésére szolgál. Rendkívül gazdagon paraméterezhető, és támogatja a megtalált fájlok feldolgozását is. A működését példákon keresztül mutatom meg.

A leggyakrabban úgy használom, hogy egy könyvtárból kiindulva keresek fájlt vagy fájlokat, amelyeknek ismerem a nevét vagy annak jellemző részletét. Ezeket a parancsban paraméterként kell megadni. A példában a etc könyvtárban és annak alkönyvtáraiban keresem a passwd fájlt. Először a kiinduló könyvtár nevét adom meg, majd a -name kapcsoló után a keresendő fájl vagy könyvtár nevét. (A példában a találatok mellett több sorrnyi hibaüzenet is megjelenik, mert egyszerű felhasználóként nincs olvasási jogosultságom néhány könyvtárra.)

feri@columbo:~/demo$ find /etc -name passwd
find: „/etc/vmware-tools/GuestProxyData/trusted”: Engedély megtagadva
/etc/pam.d/passwd
find: „/etc/chatscripts”: Engedély megtagadva
/etc/cron.daily/passwd
find: „/etc/ssl/private”: Engedély megtagadva
find: „/etc/ppp/peers”: Engedély megtagadva
find: „/etc/apt”: Engedély megtagadva
find: „/etc/polkit-1/localauthority”: Engedély megtagadva
/etc/passwd

Megismétlem a parancsot úgy, hogy a hibaüzeneteket a /dev/null fájlba irányítom. Most már jobban látható, hogy három passwd nevű fájl van a /etc könyvtárból indulva:

feri@columbo:~/demo$ find /etc -name passwd 2>/dev/null
/etc/pam.d/passwd
/etc/cron.daily/passwd
/etc/passwd

A find esetében használhatod a helyettesítő karaktereket is a keresendő fájl vagy könyvtár nevének megadásakor:

feri@columbo:~/demo$ find /etc -name 'a?d*.conf' 2>/dev/null
/etc/adduser.conf
/etc/init/atd.conf

9.1.1. Típus

Lehetőséged van arra is, hogy csak fájlt, könyvtárt, linket vagy más típusú elemet keress, ehhez a -type paraméter után kell megadnod a keresett bejegyzés típusát. A példában a passwd nevű fájlokat szeretném megkeresni a /etc könyvtárban, ezért a -type f kapcsolót használom.

feri@columbo:~/demo$ find /etc -name passwd -type f 2>/dev/null
/etc/pam.d/passwd
/etc/cron.daily/passwd
/etc/passwd

A -type lehetséges értékei:

f:Fájl
d:Könyvtár
l:Softlink
c:Karakteres eszközfájl
b:Blokkos eszközfájl
s:Socket
p:Named pipe

A socketről és a named pipe-ról később olvashatsz. TODO hol

9.1.2. Mélység

A fenti példákban is láthattad, hogy a find a keresést nem csak a megadott könyvtárban végzi, hanem az abból nyíló összesben is. Ha ezen változtatni akarsz, a -mindepth és a -maxdepth paramétereket használhatod. Mindkettő után meg kell adnod, hogy milyen mélységig akarsz keresni. A -maxdepth 1 megadásával a megadott könyvtár alatt egy szinttel még megtörténik a keresés, de az alatt már nem. A -mindepth hasonlóan működik, de ezzel a minimális keresési mélységet állíthatod be. Az alábbi példában csak az /etc könyvtárban és egy szinttel alatt keresem a passwd nevű fájlokat.

feri@columbo:~/demo$ find /etc -maxdepth 1 -type f -name passwd
/etc/passwd

Fontos, hogy ha használod ezeket a paramétereket, akkor elsőként add meg őket úgy, ahogyan a fenti példában látod.

9.1.3. Dátumok

A find néhány nagyon hasznos paramétere a fájlok különféle időpontjainak kezelésére való. Leggyakrabban a -ctime-ot szoktam használni arra, hogy egy könyvtárban egy megadott számú napnál régebben keletkezett fájlokat keresek pl. azért, mert törölni szeretném őket. Lássunk erre is egy példát, keressünk 1200 napos vagy annál öregebb fájlokat:

feri@columbo:~/demo$ find /etc -type f -ctime +1200 -name 'pa*' 2>/dev/null
/etc/pam.d/passwd
/etc/init/passwd.conf
/etc/cron.daily/passwd
/etc/pam.conf
/etc/exim4/passwd.client

A -ctime paramétere tehát a napok száma, melyet előjellel vagy anélkül írhatsz le. A +3 azt jelenti, hogy a mai dátumnál három nappal vagy korábban keletkezett fájlokat keresed. A -5 pedig azt, hogy a fájl dátuma a mai napétól legfeljebb 5 nappal lehet kisebb. Ha nem használsz előjelet, akkor a pontos napszámot adod meg.

Az -atime ugyanígy működik, de a fájl utolsó olvasására, az -mtime az utolsó módosítás dátumára vonatkozik.

Ha nem napokkal szeretnél dolgozni, másik három paramétert kell használnod, a nevük: -amin, -cmin és -mmin. Ezek paramétereként perceket kell megadnod. Az alábbi példában a 30 percnél nem régebben módosított fájlokat keresem. Először nem találok ilyet, de miután hozzáírtam egy sort az egyikhez, annak módosítási dátumaa az aktuális idő lett, így a parancs ismételt kiadása után már látható ennek eredménye.

feri@columbo:~/demo$ find . -mmin 30

feri@columbo:~/demo$ echo alma >>teszt.txt

feri@columbo:~/demo$ find . -mmin -30
./teszt.txt

A dátumokkal kapcsolatos keresésekben ún. referencia fájlt is használhatsz. Ebben az esetben nem konkrét napot, vagy percet kell megadnod, hanem egy fájlt, amelyeknél fiatalabb fájlokat keresel. Az alábbi példában a helloWorld.txt fájlnál később módosított fájlokat keresem meg:

feri@columbo:~/demo$ find . -newer helloWorld.txt
./teszt.txt

9.1.4. Méret

A keresés szempontja lehet a fájl mérete is, ehhez a -size paramétert kell használnod. Hasonlóan a fájl dátumait kezelő paraméterekhez, ebben az esetben is megadhatsz pontos értéket, de használhatsz előjeles értkeket is. A mérte megadásakor prefixek is megadhatók. A +2k a 2 kbyte-nál nagyobb fájlokat, a -2k a 2 kbyte-nál kisebbeket, a 2k a pontosan 2 kbyte-osakat jelenti. Értelemszerűen, a b jelentése byte, az M megabyte-ot, a G gigabyte-ot jelent.

A példában az 1 kbyte-nál kisebb fájlokat keresem:

feri@columbo:~$ find /etc -type f -size -1k 2>/dev/null
/etc/init.d/.legacy-bootordering
/etc/resolvconf/resolv.conf.d/base
/etc/security/opasswd
/etc/update-notifier/hooks_seen
/etc/newt/palette.original
/etc/.pwd.lock
/etc/sensors.d/.placeholder

9.1.5. Jogosultság

A fájlok, könyvtárak jogosultságaira is lehet keresni, ere a -perm kapcsoló szolgál. A következő példában a /bin könyvtár setuid-es programjait keresem, ezek jogosultsága 0755.

feri@columbo:~$ find /bin -perm 4755
/bin/su
/bin/mount
/bin/ping
/bin/umount
/bin/fusermount
/bin/ping6

9.1.6. Tulajdonos, csoport

Ha adott csoport vagy tulajdonos a keresési szempont, a -group vagy a -user paraméter jelenti a megoldást.

A root csoport által birtokolt fájlok keresése a /tmp könyvtárban:

feri@columbo:~$ find /tmp -group root 2>/dev/null
/tmp
/tmp/mc-root
/tmp/vgauthsvclog.txt.0
/tmp/vmware-root

A feri felhasználó tulajdonában álló fájlok keresése a /tmp könyvtárban:

feri@columbo:~$ find /tmp -user feri 2>/dev/null
/tmp/mc-feri

9.1.7. Feldolgozás

A keresés során megtalált fájlok fel is dolgozhatók, erre a -exec paraméter szolgál. A használata gyakorlatilag egy vagy több parancs végrehajtását jelenti minden egyes megtalált fájl esetén. A parancs leírásakor az éppen megtalált fájlra a {} karakterpárral hivatkozhatsz, a parancsot lezárni a \; karakterekkel lehet.

Lássunk egy példát! Keressük meg a 100 napnál öregebb fájlokat a /tmp könyvtárban, és minden egyes megtalált fájl esetén adjuk ki az ls -l <filenev> parancsot! (Néhány példában most a sudo használatával dolgozom, hogy ne okozzon problémát a jogosultság hiánya.)

feri@columbo:~$ sudo find /tmp -mtime -100 -type f -exec ls -l {} \;
-rw-rw-r-- 1 Y2X6SX Y2X6SX 218008 júl   30 03:10 /tmp/find-ahavasi.txt
-rw-r--r-- 1 root root 8956 júl   18 12:21 /tmp/vgauthsvclog.txt.0
-rw-r----- 1 root root 4164 júl   18 12:21 /tmp/vmware-root/vmware-apploader-1525.log
-rw-r----- 1 root root 4873 júl   18 12:21 /tmp/vmware-root/vmware-apploader-1448.log
-rw-r----- 1 root root 4873 júl   18 12:21 /tmp/vmware-root/vmware-apploader-1462.log
-rw-r----- 1 root root 4517 júl   18 12:21 /tmp/vmware-root/vmware-apploader-1494.log
-rw-r----- 1 root root 4454 júl   18 12:21 /tmp/vmware-root/vmware-apploader-1438.log
-rw-r----- 1 root root 4524 júl   18 12:21 /tmp/vmware-root/vmware-apploader-1431.log

A következő példában ezeket a fájlokat áthelyezem a /tmp/backup könyvtárba úgy, hogy a -exec paramétereként a mv {} /tmp/backup ; parancs végrehajtását határozom meg:

feri@columbo:~$ sudo find /tmp -mtime -100 -type f -exec mv {} /tmp/backup \;
feri@columbo:~$ ls -l /tmp/backup/
-rw-rw-r-- 1 Y2X6SX Y2X6SX 218008 júl   30 03:10 find-ahavasi.txt
-rw-r--r-- 1 root   root     8956 júl   18 12:21 vgauthsvclog.txt.0
-rw-r----- 1 root   root     4524 júl   18 12:21 vmware-apploader-1431.log
-rw-r----- 1 root   root     4454 júl   18 12:21 vmware-apploader-1438.log
-rw-r----- 1 root   root     4873 júl   18 12:21 vmware-apploader-1448.log
-rw-r----- 1 root   root     4873 júl   18 12:21 vmware-apploader-1462.log
-rw-r----- 1 root   root     4517 júl   18 12:21 vmware-apploader-1494.log
-rw-r----- 1 root   root     4164 júl   18 12:21 vmware-apploader-1525.log

A megtalált fájlok törlése olyan gyakori feladat, hogy erre a find esetében egy önálló kapcsolót vezettek be, ennek -delete. Használata egyszerűbb, mint az -exec paraméterezése.

feri@columbo:~$ sudo find /tmp -mtime -100 -type f -delete

9.1.8. Az xargs és a find

Ha a find parancsot az xargs-szal szeretnéd használni, problémát okozhatnak azok a fájlok, amelyeknek a nevében szóköz van. Ezeket ugyanis az xargs több fájlnévkét fogja értelmezni, hiszen a paraméterek elválasztó karaktere a szóköz. A példához létrehoztam egy olyan fájlt, amelynek a nevében szóköz van:

feri@columbo:~/demo$ touch 'Hello World.txt'
feri@columbo:~/demo$ ls -l *.txt
-rwxr-xr-x 1 feri feri  0 júl   28 22:28 helloWorld.txt
-rw-rw-r-- 1 feri feri  0 júl   30 16:49 Hello World.txt
-rw-rw-r-- 1 feri feri 46 júl   29 23:27 teszt.txt

Keressük meg a .txt kiterjesztésű fájlokat, és jelenítsük meg részletes adataikat az xargs-szal úgy, hogy az ls -l paramétereként adjuk meg őket!

feri@columbo:~/demo$ find . -name '*.txt' | xargs ls -l
ls: ./Hello nem érhető el: Nincs ilyen fájl vagy könyvtár
ls: World.txt nem érhető el: Nincs ilyen fájl vagy könyvtár
-rwxr-xr-x 1 feri feri  0 júl   28 22:28 ./helloWorld.txt
-rw-rw-r-- 1 feri feri 46 júl   29 23:27 ./teszt.txt

Látható, hogy a Hello World.txt zavart okoz, az xargs két paraméterként kezeli. A megoldást az jelenti, hogy mind a find, mind az xargs számára jelezzük, hogy a fájlok neveit a régi jó C-s formában, a 0-s kódú karakterrel zárva kezeljük. Ebben az esetben a fájlnévben levő szóköz már nem számít az xargs-nak, mert a záró 0 kódú karaktert fogja használni. A fenti példában ezért a find számára egy -print0 paramétert adok, ezzel 0-val terminált stringekként képzi a fájlneveket, az xargs-nak pedig egy -0 paramétert, amivel az 0-val zárt stringként várja az egyes paramétereket. Példánk ennek megfelelően így alakul:

feri@columbo:~/demo$ find . -name '*.txt' -print0 | xargs -0 ls -l
-rwxr-xr-x 1 feri feri  0 júl   28 22:28 ./helloWorld.txt
-rw-rw-r-- 1 feri feri  0 júl   30 16:49 ./Hello World.txt
-rw-rw-r-- 1 feri feri 46 júl   29 23:27 ./teszt.txt

Danger

Az xargs használata esetén érdemes mindig ezt a módszert használni, mert ha pl. fájlok törlését akarod így elvégezni, könnyen érhet kellemetlen meglepetés. Ilyen lehet, haHa a törlendő fájlok nevében szóköz van, netán a töredékek nevével van olyan fájl is, amit eredetileg nem szerettél volna törölni. (A fenti példában, ha lenne ott World.txt, az a hibás parancsod áldozatául esne.)

9.2. whereis

A whereis futtaható programok, forrás fájlok és/vagy kézikönyv fájlok keresésére szolgál úgy, hogy a keresést csak azok ajánlás szerinti tárolási helyein teszi meg. Ezek a könyvtárak sajnos Unix variánsonként eltérőek lehetnek. A legtöbb rendszerben a futtatható fájlok a /bin, az /usr/bin, az /sbin, az /usr/bin az /usr/local/bin és az /usr/local/sbin könyvtárakban vannak. A man parancs működéséhez szükséges fájloknak is az adott rendszer erre a célra szolgáló könyvtáraiban, kell lenniük ahhoz, hogy mind a man, mind a locate működjön. Lássunk egy példát: kapcsolók nélkül a parancs az említett fájltípusok mindegyikére keres:

feri@columbo:~/demo$ whereis chmod
chmod: /bin/chmod /usr/share/man/man2/chmod.2.gz /usr/share/man/man1/chmod.1.gz

A találatok szűkíthetők, megadhatod, hogy pontosan melyik típus érdekel. A -b kapcsoló csak a futtatható programokat (binárisokat), a -m a kézikönyv oldalakat, a -s a forrás fájlokat keresi. Az alábbi példában csak a chmod nevű programfájlt keresem:

feri@columbo:~/demo$ whereis -b chmod
chmod: /bin/chmod

9.3. locate

A locate parancs a működése során nem a fájlrendszerben keres, hanem egy előre elkészített adatbázisban, amely tartalmazza az egyes fájlok helyét és nevét. Az adatbázist az updatedb paranccsal lehet frissíteni. Lássunk egy példát, a chmod szóra keressünk rá a locate segítségével!

feri@columbo:~$ locate chmod
/bin/chmod
/usr/lib/mc/fish/chmod
/usr/share/man/man1/chmod.1.gz
/usr/share/man/man2/chmod.2.gz
/usr/share/man/man2/fchmod.2.gz
/usr/share/man/man2/fchmodat.2.gz

A parancs nem csak a chmod parancsot keresi meg, hanem minden olyan fájlt, aminek a nevében szerepel a chmod szó.

Azt, hogy a működés egy adatbázison alapul, az alábbi példában látható. Először létrhozok egy helloWorld fájlt, majd megpróbálom megkeresni a locate paranccsal. Látható, hogy nem kapok találatot:

feri@columbo:~/demo$ touch helloWorld
feri@columbo:~/demo$ locate helloWorld
feri@columbo:~/demo$

Most lefuttatom az adatbázis frissítésére szolgáló parancsot, az updatedb-t. Mivel ehhez felhasználóként nincs jogom, ezért rendszergazdaként teszem ezt meg. (A sudo parancsról a sudo c. fejezetben lesz majd szó.)

feri@columbo:~/demo$ sudo updatedb
[sudo] password for feri:

Mivel az updatedb parancs frissíti az adatbázisát, az ez után végrehajtott locate parancs már megtalálta a helloWorld fájlt.

feri@columbo:~/demo$ locate helloWorld
/home/feri/demo/helloWorld

Tip

Bizonyára felmerült benned a kérdés, hogy az updatedb parancsot mikor és kinek kell futtatnia? Nem tűnik jó megoldásnak, hogy azt az egyszerű felhasználó tegye. A megoldást egy ütemezett feladat jelenti. A működéséről a cron fejezetben lesz szó.

9.4. which

A which parancs futtatható fájlokat keres a $PATH környezeti változóban meghatározott könyvtárakban keres. Mielőtt megnézzük a működését, nézzük meg a $PATH tartalmát!

feri@columbo:~/demo$ echo $PATH
/usr/local/bin:/usr/bin:/bin:/usr/local/games:/usr/games

Keressünk rá a chmod parancsra! Ez a /bin könyvtárban van, ami a $PATH változó könyvtáraiban meg is található:

feri@columbo:~/demo$ which chmod
/bin/chmod

Ha az előző példában látott helloWorld fájlra keresnék rá ezzel, nem kapnék találatot, hiszen az aktuális könyvtár nem szerepel a $PATH változóban. Mivel csak futtatható fájlok jöhetnek szóba, először beállítom ezt:

feri@columbo:~/demo$ chmod 755 helloWorld

Majd elvégezzük a keresést, és látjuk, hogy nincs találat:

feri@columbo:~/demo$ which helloWorld
feri@columbo:~/demo$

Csak a példa kedvéért most elkövetem azt a disznóságot, hogy az aktuális könyvtárat is ráteszem a keresési útvonalra. Ahogyan a path-reference-label c. részben már láttad, ezt egy éles rendszerben veszélyes lenne beállítani.

feri@columbo:~/demo$ PATH=$PATH":."
feri@columbo:~/demo$ echo $PATH
/usr/local/bin:/usr/bin:/bin:/usr/local/games:/usr/games:.

feri@columbo:~/demo$ which helloWorld
./helloWorld

Tip

A fentiek alapján az egyes parancsok célszerű felhasználási területe:

find:Ha a keresett fájl bárhol lehet a fájlrendszerben, vagy speciális feltételeket akarsz megadni a kereséshez.
locate:Ha parogramfájt, kézikönyv oldalt vagy forrás fájlt keresel.
which, whereis:Ha kifejezetten programfájlt keresel, és fontos a gyors válaszidő.