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 teed tingimuste järgi | leitud failide ja kaustade 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 veaga “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
Kiirspikker
find . -type fleiab failidfind . -name '*.txt'leiab nime järgifind ... -print0väljastab nullmärgiga eraldatud tulemusedxargs -0loeb nullmärgiga eraldatud sisendi õigesti sissefind ... -exec käsk {} +on sageli lihtne alternatiivxargs-ile
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 find-ist 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 enne teha kuivem kontroll:
find . -type f -name '*.log'
ja alles siis panna lõppu päris tegevus.
Veel parem on alustada mittelahutava käsuga nagu:
find . -type f -name '*.log' -print0 | xargs -0 ls -lh
Tüüpilised kasutused
- leia kõik kindla laiendiga failid
- anna need failid edasi
wc,grep,lsvõi mõnele skriptile - väldi failinimede lõhkumist tühikute peal
Kui find ja xargs on tuttavad, on loomulik järgmine samm kasutada neid koos tekstiotsingu või shelliskriptidega.
Päris näide: loenda kõik data/ tekstifailid kokku
Repo data/ kaust on hea 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: ohutu alternatiiv -exec
Sama töö saab sageli teha ka ilma xargs-ita:
find otsi-naide -type f -name '*.txt' -exec wc -l {} +
See on sageli kõige lihtsam kuju siis, kui:
- tahad ühe käsu kõikidele tulemustele rakendada
- ei taha mõelda sisendi eraldamisele eraldi torus
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.
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
data/kausta 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 fainult failid-name '*.txt'nime järgi-print0ohutu eraldusxargs -0loe ohutult-exec {} +käivita otseread -r -d ''loe nullmärgini