find ja xargs ohutumalt
Selles peatükis vaatame, kuidas kasutada find-i ja xargs-i nii, et tühikud ja keerulised failinimed ei lõhuks tulemust ära.
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
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
See peatükk seostub hästi teemadega Teksti otsimine: grep ja sugulased ja Esimene shelliskript.
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.