Mustand: sisu ei ole veel tehniliselt ega keeleliselt täielikult kontrollitud ega toimetatud.

Peatüki vaade

Linux/Unix/macOS käsurea kiirõpik

Praegu loed peatükki `find` ja `xargs` ohutumalt, mis kuulub osasse Osa IV: Tekst, otsing ja automatiseerimine.

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 ... -print0
  • xargs -0

Kiirülevaade

Eesmärk on failipuus tegutseda nii, et tühikud ja muud keerulised failinimed tulemust ei lõhuks.

Käsk või kujuMilleksMida tavaliselt näed
find ...leia teed tingimuste järgileitud failide ja kaustade teed
xargsanna teed järgmisele käsulejärgmise käsu väljund
-print0eralda nimed nullmärgigamasinloetav voog, mitte tavalised read
xargs -0loe nullmärgiga nimesidtühikutega nimed jäävad terveks
-exec ... {} +käivita käsk otse find seesjä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 -exec oleks lihtsam
  • testimata käsk pannakse kohe muutma või kustutama

Kiirspikker

  • find . -type f leiab failid
  • find . -name '*.txt' leiab nime järgi
  • find ... -print0 väljastab nullmärgiga eraldatud tulemused
  • xargs -0 loeb nullmärgiga eraldatud sisendi õigesti sisse
  • find ... -exec käsk {} + on sageli lihtne alternatiiv xargs-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 -print0 eraldab tulemused nullmärgiga
  • xargs -0 loeb 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 -0 on 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 -print0 annab failinimed ohutult edasi
  • read -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:

  • rm
  • chmod
  • mv

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, ls võ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:

  • find leiab kõik .txt failid
  • -print0 eraldab need ohutult
  • xargs -0 wc -l annab 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 xargs võiks need lõhkuda
  • -print0 | xargs -0 hoiab 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

  1. Loo vähemalt üks fail, mille nimes on tühik.
  2. Leia see fail find-iga.
  3. Näita seda faili ls -l abil läbi töövoo -print0 | xargs -0.
  4. Seleta ühe lausega, miks -print0 ja -0 koos käivad.
  5. Loenda data/ kausta tekstifailide read käsuga find ... -print0 | xargs -0 wc -l.
  6. 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 failid
  • find . -type f -name '*.txt' -print0 | xargs -0 wc -lloe read ohutult
  • find . -type f -name '*.log' -exec ls -lh {} +käivita otse
  • find 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 eraldus
  • xargs -0loe ohutult
  • -exec {} +käivita otse
  • read -r -d ''loe nullmärgini