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 Esimene shelliskript, mis kuulub osasse Osa IV: Tekst, otsing ja automatiseerimine.

Esimene shelliskript

Selles peatükis teeme väga väikese esimese shelliskripti ja vaatame, mida tähendavad shebang, chmod +x, argumendid, if, for ja exit code.

Loogika

Shelliskript on lihtsalt tekstifail, kus on järjest käsud, mida shell käivitab.

Esimese skripti eesmärk ei ole veel teha midagi keerulist. Piisab sellest, kui saad kätte viis põhiasja:

  1. kuidas skript algab
  2. kuidas ta käivitatavaks teha
  3. kuidas talle argumente anda
  4. kuidas teha lihtne tingimus
  5. kuidas tagastada edu või viga

Kiirspikker

  • #!/usr/bin/env bash valib Bashi
  • chmod +x fail.sh teeb faili käivitatavaks
  • $1 tähendab esimest argumenti
  • "$@" tähendab kõiki argumente
  • if ... fi teeb tingimusloogika
  • for ... do ... done kordab tegevust
  • exit 0 tähendab edu, exit 1 tähendab viga

Käivita need käsud


mkdir -p skripti-naide
cd skripti-naide
cat > tervita.sh <<'EOF'
#!/usr/bin/env bash
if [ $# -eq 0 ]; then
  echo "Kasuta: $0 nimi..." >&2
  exit 1
fi
for nimi in "$@"; do
  echo "Tere, $nimi!"
done
EOF
chmod +x tervita.sh
./tervita.sh Mari Jaan
./tervita.sh
echo $?

Skripti loomine heredoc-iga

Skripti ei pea alati kokku panema pika printf käsuga. Väga tavaline ja loetav viis on kasutada here-doc'i.

Näide:


cat > tere.sh <<'EOF'
#!/bin/sh
echo "Tere skriptist"
pwd
EOF

Selle loogika on:

  • cat > tere.sh kirjutab väljundi faili tere.sh
  • <<'EOF' tähendab, et järgmised read lähevad faili kuni reale EOF
  • jutumärkides EOF hoiab ära selle, et shell hakkaks neid ridu juba loomise hetkel ise laiendama

See on väga mugav, kui skript on juba mitmerealine.

sh skript.sh, bash skript.sh, zsh skript.sh ja ./skript.sh

See on üks kõige tähtsamaid erinevusi shelliskriptide juures.

Need käsud ei tähenda päris sama asja:


sh skript.sh
bash skript.sh
zsh skript.sh
./skript.sh

Praktiline loogika on:

  • sh skript.sh käsib fail sisu tõlgendada shellil sh
  • bash skript.sh käsib fail sisu tõlgendada Bashil
  • zsh skript.sh käsib fail sisu tõlgendada Zsh-l
  • ./skript.sh kasutab skripti shebang-rida

See tähendab väga tähtsat asja:

  • kui käivitad bash skript.sh, siis otsustab tõlgendaja sina käsureal
  • kui käivitad ./skript.sh, siis otsustab tõlgendaja skripti esimene rida

Seepärast ei ole shebang ainult "ilus esimene rida", vaid päris käitumise osa.

Väike võrdlusnäide

Loo kõigepealt väga lihtne skript:


cat > naide.sh <<'EOF'
#!/bin/sh
echo "shell: $0"
echo "pwd: $(pwd)"
EOF

Nüüd proovi:


sh naide.sh
bash naide.sh
zsh naide.sh
chmod +x naide.sh
./naide.sh

Kõik need võivad selle lihtsa skripti puhul töötada, sest skript kasutab väga tavalist ja ühilduvat süntaksit.

See on hea esimene õppetund:

  • lihtne POSIX-laadne skript töötab sageli mitmes shellis
  • keerulisemad Bashi või Zsh eripärad enam mitte

Millal sh ja millal bash

Hea rusikareegel on:

  • kui skript kasutab ainult lihtsat ja laialt ühilduvat süntaksit, sobib #!/bin/sh
  • kui skript kasutab Bashi erisusi, siis kasuta #!/usr/bin/env bash

Näiteks Bashi-spetsiifiline on sageli:

  • [[ ... ]]
  • massiivid
  • mõni mugavam parameetrilaiendus

Näide, mis töötab Bashis, aga mitte tingimata sh-s


cat > bash-only.sh <<'EOF'
#!/usr/bin/env bash
nimi="Mari"
if [[ $nimi == M* ]]; then
  echo "See on Bashi [[ ]] naide"
fi
EOF

Käivita:


bash bash-only.sh
chmod +x bash-only.sh
./bash-only.sh

Kui proovid sama käsuga:


sh bash-only.sh

siis võib see anda vea, sest sh ei pruugi Bashi süntaksit toetada.

Just siin tuleb shebang ja õige tõlgendaja valik päriselt mängu.

Shebang

Skripti esimene rida:


#!/usr/bin/env bash

ütleb, millise tõlgendiga see fail käivitada.

See on põhjus, miks sama tekstifail võib käituda skriptina, mitte lihtsalt tavalise tekstina.

Kui käivitad faili kujul:


./skript.sh

siis süsteem ei "arva niisama", et see on Bash või Zsh. Ta vaatab faili algust.

Kui esimene rida on näiteks:


#!/bin/sh

siis püütakse fail käivitada shelliga sh.

Kui esimene rida on:


#!/usr/bin/env perl

siis püütakse fail käivitada Perliga.

See tähendab:

  • täitmisõigus ütleb, et faili tohib käivitada
  • shebang ütleb, millega seda käivitada

Mõlemat on sageli vaja korraga.

Näide: sama idee teise tõlgendajaga

Skript ei pea olema ainult shelliskript. Sama loogika töötab ka teiste tõlgendatud keeltega.

Näide:


cat > tere.pl <<'EOF'
#!/usr/bin/env perl
print "Tere Perl-ist\n";
EOF
chmod +x tere.pl
./tere.pl

Siin:

  • fail on tavaline tekstifail
  • täitmisõigus lubab selle käivitada
  • shebang ütleb süsteemile, et faili peab lugema Perl

Kui Perl puudub, siis ei saa faili käivitada, isegi kui chmod +x on tehtud.

chmod +x

Faili sisu üksi ei tee sellest veel käivitatavat skripti.

Selleks on vaja:


chmod +x tervita.sh

Pärast seda saad käivitada:


./tervita.sh Mari

Kui täitmisõigust ei ole, siis võid testi jaoks käivitada ka nii:


bash tervita.sh Mari

Või:


sh tervita.sh Mari
zsh tervita.sh Mari

Aga siis valid shelli sina käsureal, mitte skript ise shebang-reaga.

Argumendid

Kui kirjutad:


./tervita.sh Mari Jaan

siis:

  • $1 on Mari
  • $2 on Jaan
  • "$@" tähendab kõiki argumente koos

Esimese skripti juures on "$@" väga kasulik, sest saad ühe korraga läbi käia kõik antud nimed.

if

Selles skriptis on tingimus:


if [ $# -eq 0 ]; then

Selle mõte on:

  • kui argumente ei antud
  • siis näita kasutusjuhendit
  • ja lõpeta veakoodiga

See on väga tavaline muster.

for

Tsükkel:


for nimi in "$@"; do
  echo "Tere, $nimi!"
done

käib kõik argumendid ükshaaval läbi.

See on esimese skripti juures hea näide, sest seal on kohe näha, kuidas üks väike tööriist saab mitut sisendit töödelda.

Exit code

exit code on väga tähtis, sest see ütleb teistele programmidele ja shellile, kas töö õnnestus.

Tavaline rusikareegel:

  • 0 tähendab edu
  • muu arv tähendab viga

Selles skriptis:

  • ilma argumentideta lõpetab ta exit 1
  • argumentidega lõpetab ta edukalt

Pärast käsu jooksutamist saad viimast koodi vaadata nii:


echo $?

Minitest

  1. Tee oma skript, mis tervitab ühte või mitut nime.
  2. Muuda see käivitatavaks.
  3. Käivita skript nii argumentidega kui ilma argumentideta.
  4. Vaata echo $? abil, mis exit code jäi viimase käigu järel.
  5. Seleta ühe lausega, mis roll on shebang'il.
  6. Loo üks skript here-doc'i abil kujul cat > skript.sh <<'EOF'.
  7. Proovi vahet sh skript.sh ja ./skript.sh vahel.