find ja xargs ohutumalt
Loogika
find leiab teed.
xargs annab need teed järgmisele käsule edasi.
Probleem tekib siis, kui failinimedes on:
- tühikud
- tabulaatorid
- reavahetused
Kui kasutada naiivset kuju, siis võib üks failinimi laguneda mitmeks tükiks. Sellepärast on oluline paar:
find ... -print0xargs -0
Kiirülevaade
Eesmärk on failipuus tegutseda nii, et tühikud ja muud keerulised failinimed tulemust ei lõhuks.
| Käsk või kuju | Milleks | Mida tavaliselt näed |
|---|---|---|
find ... | leia kirjeid tingimuste järgi | leitud failide ja kataloogide teed |
xargs | anna teed järgmisele käsule | järgmise käsu väljund |
-print0 | eralda nimed nullmärgiga | masinloetav voog, mitte tavalised read |
xargs -0 | loe nullmärgiga nimesid | tühikutega nimed jäävad terveks |
-exec ... {} + | käivita käsk otse find sees | järgmise käsu väljund |
Vale eraldusviis lõpeb sageli veateatega No such file or directory, sest failinimi lõigatakse tükkideks.
Tüüpilised algaja vead
- eeldatakse, et kõik failinimed on lihtsad ühe sõnaga nimed
- kasutatakse
xargs-it pimesi seal, kus-execoleks lihtsam - testimata käsk pannakse kohe muutma või kustutama
Käivita need käsud
find . -type f -name '*.txt'
find . -type f -name '*.txt' -print0 | xargs -0 wc -l
find . -type f -name '*.log' -exec ls -lh {} +
Kui tahad näha just keeruliste nimede loogikat, tee väike näide:
mkdir -p find-naide
cd find-naide
touch 'üks fail.txt' 'teine fail.txt'
find . -type f -name '*.txt' -print0 | xargs -0 ls -l
Miks -print0 ja -0 tähtsad on
Vaikimisi eraldatakse käsurea tekst sageli tühikute ja reavahetuste järgi. See tähendab, et fail nimega:
minu fail.txt
võib naiivses töövoos käituda nagu kaks eri sõna.
Selle vältimiseks:
find -print0eraldab tulemused nullmärgigaxargs -0loeb just seda vormi
See on praktiline „ohutu vaikevariant“, kui liigud käsult find järgmise käsuni.
xargs või -exec?
Mõlemad on kasulikud.
Näide xargs-iga:
find . -type f -name '*.txt' -print0 | xargs -0 wc -l
Näide -exec-iga:
find . -type f -name '*.txt' -exec wc -l {} +
Rusikareegel:
- kui tahad lihtsat ja ohutut kuju, siis
-exec ... +on sageli väga hea - kui tahad teadlikult ehitada torupõhist töövoogu, siis
-print0 | xargs -0on tugev valik
xargs vs while read
On veel üks väga kasulik kuju:
find data -type f -name '*.txt' -print0 |
while IFS= read -r -d '' fail; do
wc -l "$fail"
done
Selle loogika on:
find -print0annab failinimed ohutult edasiread -r -d ''loeb ühe nullmärgiga eraldatud faili korraga- tsüklis saad iga faili kohta teha rohkem kui ühe sammu
xargs on väga hea siis, kui:
- tahad ühe käsu kiiresti paljudele failidele anda
while read on eriti hea siis, kui:
- tahad iga faili kohta teha väikese loogika
- vajad tsüklit, tingimust või mitut käsku järjest
Näiteks:
find data -type f -name '*.txt' -print0 |
while IFS= read -r -d '' fail; do
echo "Töötlen: $fail"
head -n 1 "$fail"
done
Väldi pimesi hävitavaid käske
find ja xargs lähevad eriti ohtlikuks siis, kui lõppu pannakse:
rmchmodmv
Seetõttu tasub alati alustada ohutu eelvaatega:
find . -type f -name '*.log'
ja alles siis lisada lõppu faile muutev tegevus.
Veel parem on alustada mittehävitava käsuga, näiteks:
find . -type f -name '*.log' -print0 | xargs -0 ls -lh
Päris näide: loenda kõik data/ tekstifailid kokku
Repo kataloog data/ on turvaline koht find-i harjutamiseks.
find data -type f -name '*.txt' -print0 | xargs -0 wc -l
Siin:
findleiab kõik.txtfailid-print0eraldab need ohutultxargs -0 wc -lannab igale failile reaarvu
See on hea näide, sest siin ei ole vaja midagi kustutada ega muuta, ainult vaadata.
Päris näide: keeruliste nimedega failid
Kui tahad näha, miks -print0 ja -0 on päriselt vajalikud, tee selline väike töökaust:
mkdir -p otsi-naide/'Tallinn andmed'
cp data/sample-words.txt 'otsi-naide/Tallinn andmed/sonad 1.txt'
cp data/sample-text.txt 'otsi-naide/Tallinn andmed/tekst 2.txt'
find otsi-naide -type f -name '*.txt' -print0 | xargs -0 ls -lh
Selle töövoo mõte on:
- failinimedes on tühikud
- naiivne
xargsvõiks need lõhkuda -print0 | xargs -0hoiab need tervikuna koos
Päris näide: leia logifail ja vaata selle suurust
find data -type f -name '*.log' -exec ls -lh {} +
See on väike, aga päris praktiline muster:
- leia failid
- ära hävita midagi
- vaata enne suurust või arvu
Just nii peakski find-iga töötamine algama.
Tühi tulemus ja suured failihulgad. find ... -exec käsk {} + ei käivita käsku, kui vasteid pole. xargs -0 korral sõltub tühja sisendi käitumine süsteemist; GNU xargs võib käsu siiski käivitada. GNU valik -r väldib seda, kuid pole igal pool sama tähendusega. Suure hulga korral võib nii -exec ... + kui ka xargs jagada failid mitmeks käivituseks: näiteks wc kokkuvõte on siis partii, mitte tingimata kogu puu summa.
read -r -d '' näide eeldab Bashi või zsh-d, mitte suvalist POSIX sh-d. IFS= säilitab nime alguse ja lõpu tühikud, -r kurakriipsud ning tühi -d määrab nullmärgi eraldajaks.
Minitest
- Loo vähemalt üks fail, mille nimes on tühik.
- Leia see fail
find-iga. - Näita seda faili
ls -labil läbi töövoo-print0 | xargs -0. - Seleta ühe lausega, miks
-print0ja-0koos käivad. - Loenda kataloogi
data/tekstifailide read käsugafind ... -print0 | xargs -0 wc -l. - Tee sama töövoog uuesti kujul
while IFS= read -r -d '' fail; do ...; done.
Peatüki täisspikker
Töövood
Eesmärk
otsi failid find-iga ja anna need ohutult edasi järgmisele käsule, isegi siis, kui nimedes on tühikuid
Põhikujud
find . -type f -name '*.txt'otsi failidfind . -type f -name '*.txt' -print0 | xargs -0 wc -lloe read ohutultfind . -type f -name '*.log' -exec ls -lh {} +käivita otsefind data -type f -name '*.txt' -print0 | while IFS= read -r -d '' fail; do head -n 1 "$fail"; donetöötle ükshaaval
Olulisemad lipud, märgid ja kiirnupud
-type ffind: ainult tavafailid-name '*.txt'nime järgi-print0find: failinimede vahel nullmärkxargs -0xargs: eralda argumendid nullmärgiga-exec käsk {} +käivita otseread -r -d ''Bash/zsh: loe nullmärgini, säilita kaldkriipsud