Programování v shellových skriptech (BASH)
Milan Keršláger, 09.11.2006, 08:27:44
Úvod
Shellové skripty jsou zápisem příkazů, které bychom jinak zadávali postupně
na příkazovém řádku. Aby byl skript přímo spustitelný, musí být jméno interpretu
uvedeno na prvním řádku skriptu (hned na začátku souboru). V našem případě
bude na prvním řádku uvedeno:
#!/bin/bash
Dále musí mít skript nastaven příznak spuštění (eXecutable). Na příponě souboru
nezáleží, ale obvykle se uvádí .sh
(příponu je možné i vynechat).
Pokud chceme skript spouštět pouhým zadáním jeho jména, je potřeba ho umístit
do adresáře uvedeného v proměnné PATH
. Takovým adresářem je
obvykle automaticky adresář bin
v domácím adresáři přihlášeného
uživatele. Je-li umístěn skript jinde, musíme k němu uvést cestu, protože
shell z bezpečnostních důvodů aktuální adresář neprohledává. Komentáře se ve
skriptech označují křížkem neboli znakem hash (#). Je-li komentář započat na
začátku řádku, ignoruje shell celý řádek. Jinak ignoruje pouze text umístěný za
ním.
# použijeme oblíbený editor
mcedit priklad.sh
# nastavíme právo spuštění
chmod +x priklad.sh
# spustíme skript z aktuálního adresáře
./priklad.sh
Chceme-li vidět, jak se skript interpretuje, uvedeme na příslušném místě
skriptu příkaz set -x
a následně pak ladící výstup vypneme pomocí
set +x
. Také můžeme celý skript spustit s parametrem
-x
takto:
bash -x priklad.sh
Návratový kód
Každý příkaz v Unixu vrací návratový kód. V případě úspěchu (resp.
"pravdy") vrací ukončený program (nebo skritpt) podle dohody nulu
(0). Jsou-li při provádění příkazu zjištěny problémy, je návratový kód nenulový
(nejčastěji 1). Větší hodnoty mohou blíže specifikovat situaci, kvůli které je
vrácena chyba. Tím pádem je potřeba ve skriptech při kontrole výstupního kódu
příkazu testovat jeho nenulovost (tj. netestovat, jestli vrací 1, ale jestli
vrací 0 nebo cokoliv jiného). Pro ukonční skriptu a předání návratového kódu
slouží příkaz exit
.
# návratový kód je 1 (tj. chyba, nepravda)
exit 1
Návratový kód využívají i kontrukce podmínek a smyček, kdy se vyhodnocuje,
je-li výraz pravdivý (tj. použitý příkaz vrací nulu) nebo nepravdivý (vrací
číslo různé od nuly). V případě, že je použita ve výrazu kolona (pipe, trubka),
vyhodnocuje se pouze návratový kód posledního příkazu v koloně.
Vkládání výstupu příkazu na jeho místo
Někdy je potřeba nejprve něco spočítat nebo zpracovat a teprve výsledek
potřebujeme použít například jako parametr jiného příkazu. V tomto případě se
používá buď zpětných apostrofů (na anglické klávesnici je zpětný apostrof vlevo
vedle čísla 1 v horná řadě kláves) nebo nověji konstrukce $(...)
,
kde na místo tří teček dosadíme příkaz nebo kolon příkazů. Výhodou tohoto
způsobu je, že lze používat vnořené vyhodnocování.
Příklad: echo Písmeno x má ve jméně právě přihlášený $(who | grep x)
Ve výše uvedeném příkladu je nejprve vyhodnocen příkaz v závorkách, jeho výstup
je dosazen na původní místo příkladu a pak je teprve proveden příkaz echo.
Předávání parametrů
Podmínka if
if výraz; then příkazy1; [ elif
příkazy2; then příkazy3; ] ...
[ else příkazy4; ] fi
- pokud je návratový kód výrazu nulový (příkaz byl úspěšný,
nenastala chyba), bude provedena část příkazy1
- jinak je provedena část příkazy2 nebo příkazy4 (pokud
část elif nepoužijeme)
- návratový kód vrací poslední provedený proces nebo 0,
pokud se ještě neprovedl žádný příkaz
- pokud použijeme kolonu příkazů, bude použita návratová hodnota
posledního příkazu v koloně
Příklad: if grep -q huzva /etc/passwd; then
echo yes
else
echo no
fi
Příklad: if [ -f /tmp/IAmHere ]; then
echo jsem tu
fi
while výraz; do příkazy; done
until výraz; do příkazy; done
for jméno [ in slovo; ] do příkazy; done
case slovo in
vzorek [ |
vzorek ... ]) příkazy;;
...
esac
- break [n]
- ukončí n-tou úroveň cyklu for, while, until
- continue [n]
- zahájí další iteraci cyklu
- true
- návratový kód vždy 0
- false
- návratový kód vždy 1
Příklad: while true; do
echo y
done # ekvivalent příkazu yes
test výraz
[ výraz ]
- obě uvedené formy jsou ekvivalentní (tj. chovají se naprosto stejně),
[ je linka na příkaz test
- příkaz vyhodnotí výraz a nastaví návratový kód 0 (true) nebo 1 (false)
- místo příkazu if lze s výhodou použít zkrácenou formu:
- [ výraz ] && příkaz
- příkaz je proveden, pokud výraz vrátí pravdu
- [ výraz ] || příkaz
- příkaz je proveden, pokud výraz vrátí nepravdu
- Testování typu souboru
- -f soubor
- soubor existuje a je normálním souborem
- -d soubor
- soubor existuje a je adresářem
- -h soubor nebo -L soubor
- soubor existuje a je symbolickým odkazem
- -b soubor
- soubor existuje a je blokovým speciálním souborem
- -c soubor
- soubor existuje a je znakovým speciálním souborem
- -e soubor
- soubor existuje (pouze vestavěný příkaz test)
- -p soubor
- soubor existuje a je pojmenovanou rourou
- -S soubor
- soubor existuje a je socket
- -t [fd]
- fd je otevřeno na terminál, vynecháme-li fd,
potom se použije hodnota 1 (standardní výstup)
Příklad: if [ -f /etc/shadow ]; then
echo "V systému je nainstalováno shadow password"
fi
- Testování přístupových práv
- -r soubor
- soubor existuje a lze jej číst
- -w soubor
- soubor existuje a lze do něj zapisovat
- -x soubor
- soubor existuje a je proveditelný
- -u soubor
- soubor existuje a má nastaven SUID bit
- -g soubor
- soubor existuje a má nastaven SGID bit
- -k soubor
- soubor existuje a má nastaven sticky bit
- Testování charakteristik souborů
- -e soubor
- soubor existuje
- -s soubor
- soubor existuje a má velikost větší než nula
- soubor1 -nt soubor2
- soubor1 je novější (podle času poslední modifikace
obsahu) než soubor2
- soubor1 -ot soubor2
- soubor1 je starší (podle času poslední modifikace
obsahu) než soubor2
- soubor1 -ef soubor2
- soubor1 a soubor2 jsou na stejném zařízení
a mají stejné číslo i-uzlu (tzn. jde o dva tvrdé odkazy na
tentýž soubor)
- Testování řetězců
- -z řetězec
- délka řetězce je nulová
- -n řetězec nebo řetězec
- délka řetězce je nenulová
- řetězec1 = řetězec2
- řetězce jsou shodné
- řetězec1 != řetězec2
- řetězce se neshodují
Příklad: [ -z $HOME ] && echo "Proměnná prostředí HOME neexistuje"
- Numerické testy
- na místě numerického argumentu se smí vyskytovat buď číslo
(může být i záporné), nebo speciální výraz
- -l řetězec
- výraz je nahrazen délkou řetězce
- číslo1 -eq číslo2
- číslo1 = číslo2
- číslo1 -ne číslo2
- číslo1 se nerovná číslo2
- číslo1 -lt číslo2
- číslo1 < číslo2
- číslo1 -le číslo2
- číslo1 je menší nebo rovno číslo2
- číslo1 -gt číslo2
- číslo1 > číslo2
- číslo1 -ge číslo2
- číslo1 je větší nebo rovno číslo2
Příklad: i=1
while [ $i -le 10 ]; do
echo $i
i=`expr $i + 1`
done
Příklad: test -l abc -gt 1 && echo je delší
- Logické výrazy
- priority lze upravovat závorkami ( )
- Pozor: nezapomenout zrušit speciální význam závorky
v shellu - např. pomocí zpětného lomítka
\( \)
- ! výraz
- výraz je nepravdivý.
- výraz1 -a výraz2
- výraz1 a výraz2 jsou pravdivé
- výraz1 -o výraz2
- výraz1 nebo výraz2 je pravdivý
Příklad: [ ! -z $HOME ] && echo "Proměnná prostředí HOME existuje"