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 sed, awk ja perl praktiliselt, mis kuulub osasse Osa IV: Tekst, otsing ja automatiseerimine.

sed, awk ja perl praktiliselt

Selles peatükis teeme sissejuhatuse voopõhisesse tekstimuutmisse, väljade töötlemisse ja perl-i one-lineritesse.

Loogika

sed, awk ja perl on kasulikud siis, kui lihtsast filtreerimisest enam ei piisa, aga eraldi programmi kirjutamine oleks liiga palju. Need on seotud tekstivoo peatükkidega, sest töötavad peamiselt ridade, väljade ja mustrite peal.

Hea tööjaotus on sageli selline:

  • sed lihtsateks asendusteks
  • awk väljade ja veergude töötlemiseks
  • perl siis, kui vaja on tugevamat regulaaravaldiste loogikat või natuke rikkamat ühe rea programmi

Kiirspikker

  • sed 's/vana/uus/' asendab esimese vaste real
  • sed 's/vana/uus/g' asendab kõik vasted real
  • awk '{print $1}' trükib esimese välja
  • awk -F: '{print $1}' kasutab koolonit eraldajana
  • perl -pe 's/vana/uus/g' käib read läbi ja prindib tulemuse välja
  • perl -ne 'print if /muster/' käib read läbi, aga prindib ainult siis, kui tingimus sobib
  • perl -e '...' käivitab antud Perl-koodi otse käsurealt

Käivita need käsud


echo 'kass koer kass' | sed 's/kass/rebane/'
echo 'kass koer kass' | sed 's/kass/rebane/g'
Terminali näide, kus fail `tere.txt` kopeeritakse failiks `kere.txt`, seejärel tehakse käsuga `sed 's/vana/uus/'` uus fail `mere.txt`, ja `head *` abil võrreldakse kõigi kolme faili algust.
Terminali näide, kus fail tere.txt kopeeritakse failiks kere.txt, seejärel tehakse käsuga sed 's/vana/uus/' uus fail mere.txt, ja head * abil võrreldakse kõigi kolme faili algust.

Selle pildi loogika on järgmine:

  1. echo "Tere tere vana kere" > tere.txt loob algse faili
  2. cp tere.txt kere.txt teeb samast sisust koopia
  3. sed 's/vana/uus/' tere.txt > mere.txt loeb faili tere.txt, asendab esimese vaste ja kirjutab tulemuse uude faili
  4. head * näitab kolme faili algust kõrvuti

Oluline tähelepanek on see, et sed ei muuda siin algset faili kohapeal. Tulemuse saab uude faili suunata märgiga >.

Üks asendus või kõik asendused

sed-i üks kõige tähtsamaid erinevusi on see, kas tehakse üks asendus või kõik asendused real.

Terminali näide, kus failis `tere.1.txt` tehakse kõigepealt käsk `sed 's/ere/ERE/'`, mis muudab ainult esimese vaste, ja seejärel `sed 's/ere/ERE/g'`, mis muudab kõik vasted.
Terminali näide, kus failis tere.1.txt tehakse kõigepealt käsk sed 's/ere/ERE/', mis muudab ainult esimese vaste, ja seejärel sed 's/ere/ERE/g', mis muudab kõik vasted.

Selle pildi sees on näha kaks väga erinevat tulemust:

  1. sed 's/ere/ERE/' tere.1.txt > tere.2.txt muudab ainult rea esimese vaste
  2. sed 's/ere/ERE/g' tere.1.txt > tere.3.txt muudab kõik vasted samal real
  3. head * näitab pärast kõiki kolme faili kõrvuti, nii et vahe on kohe nähtav

Rusikareegel on lihtne:

  • ilma g-ta muudetakse tavaliselt ainult esimene vaste real
  • g tähendab global, ehk kõik vasted sellel real

printf 'Mari:20\nJaan:21\n' | awk -F: '{print $1}'
printf 'Mari:20\nJaan:21\n' | awk -F: '{print $1, $2}'

echo 'kass koer kass' | perl -pe 's/kass/rebane/g'
printf 'Mari\nJaan\n' | perl -ne 'print if /Ja/'
printf 'Mari:20\nJaan:21\n' | perl -F: -lane 'print $F[0]'

perl one-linerite loogika

Kui kirjutad:


perl -pe 's/kass/rebane/g'

siis:

  • -e tähendab, et kood tuleb käsurealt
  • -p tähendab, et Perl loeb sisendi rida-realt läbi ja prindib iga rea vaikimisi välja

See teeb perl -pe kuju väga heaks voopõhisteks asendusteks.

Kui kirjutad:


perl -ne 'print if /Ja/'

siis:

  • -n tähendab, et Perl käib read küll läbi, aga ei prindi neid automaatselt
  • sina otsustad ise, millal print teha

See kuju on kasulik siis, kui tahad teha väikest tingimusloogikat.

Fun fact: algarvud regexiga

See järgmine näide ei ole kõige praktilisem viis algarvude leidmiseks, aga ta on väga hea näide sellest, kui veidralt võimsad võivad perl-i one-linerid olla:


seq 2 200 | perl -nlE 'say if ("a" x $_) !~ /^(aa+)\1+$/'

See kuju on siin meelega võimalikult lihtne. Kuna alustame vahemikku 2-st, ei pea me eraldi 0 ja 1 juhtumeid regexis välja filtreerima.

Mõte on selline:

  • iga arv teisendatakse ajutiselt ühe tähe korduseks, näiteks 7 muutub kujule aaaaaaa
  • regex proovib leida, kas see rida koosneb mingist väiksemast plokist, mida saab mitu korda korrata
  • kui saab, siis arv ei ole algarv
  • kui ei saa, siis prinditakse arv välja

See tähendab sisuliselt: “prindi ainult need arvud, mida ei saa kirjutada kujul m * n, kus mõlemad on suuremad kui 1.”

Praktilises skriptis oleks tavaliselt mõistlikum kasutada tavapärast jaguvuskontrolli, aga ühe rea triki või loengu-näite jaoks on see väga meeldejääv.

Millal mida kasutada

  • sed sobib lihtsaks voopõhiseks asenduseks
  • awk sobib väljade ja ridade töötlemiseks
  • perl sobib keerukamaks mustriloogikaks, mitmeks asenduseks või natuke rikkamaks ühe rea programmiks

Näiteks:

  • kui tahad lihtsalt sõna välja vahetada, siis sed on sageli kõige loetavam
  • kui tahad võtta teisest veerust väärtuse, siis awk on sageli kõige loomulikum
  • kui tahad korraga filtreerida, asendada ja kasutada tugevamaid regex'e, siis perl võib olla kõige mugavam

Kui töö kasvab keerukaks, võib mõnikord olla selgem kasutada Pythonit. Aga väikeste ühekordsete ülesannete jaoks on sed, awk ja perl väga tugevad.

Minitest

  1. Asenda reas üks sõna teisega.
  2. Võta välja kooloniga eraldatud faili esimene väli.
  3. Prindi awk abil ainult teine veerg.
  4. Filtreeri perl -ne abil välja ainult need read, kus on kindel muster.
  5. Tee perl -pe abil globaalne asendus kogu sisendi ulatuses.