S test
om si treba dať pozor na pár zádrheľov. Keďže premenné v shelli nemajú dátové typy (všetko je reťazec, string), je potrebné akýmsi sposôbom rozlišovať, či chceme porovnávať reťazce, čísla alebo súbory.
Reťazcové operátory
Test neprázdnosti premennej
Ak chceme zistiť, či premenná nie je prázdna (resp. či je definovaná):
DISTRO="debian"
test "$DISTRO"
Výsledkom (exit code) je 0
.
Opačný príklad s exit code 1:
test "$GURBLEBURBLE"
Pozor na povinnosť vložiť názov premennej do úvodzoviek! Inak sa budú diať čudné veci. Skúsme si:
NIC=
test $NIC
V tomto prípade je exit code 1. Ešte pred vykonaním test
u prebehla expanzia!
test $NIC
test
Čo znamená, že test
sa zavolá bez argumentov a v takom prípade vždy vracia exit code 1.
Test neprázdnosti premennej (alternatívny)
Ekvivalentný zápis:
DISTRO="debian"
test -n "$DISTRO"
Test prázdnosti premennej: operátor -z
Opakom -n
(nonzero length) je -z
(zero length)
test -z "$NEDEFINOVANA"
Test identických reťazcov
Porovnanie reťazcov je jednoduché, ale pozor, používa sa jednoduché =
. Pascalisti sa potešia, Cčkari posmutnejú:
DISTRO="debian"
test $DISTRO = "debian"
echo $?
Výsledkom je samozrejme 0
.
Pozor na syntax! Okolo =
musia byť medzery! Ak ich vynecháte, opäť: začnú sa diať čudesné veci! Ukážka expanzie:
DISTRO="ubuntu"
test $DISTRO="debian"
test ubuntu=debian
Test bude zavolaný s jedným parametrom a v takom prípade je správanie jednoznačné: testuje sa, či parameter nie je prázdny. Samozrejme, ubuntu=debian
nie je prázdny a tak výsledkom je vždy 0 napriek tomu, že to nie je pravda.
Test rozličných reťazcov
Nezhoda reťazcov sa rieši už cez klasický !=
test $DISTRO != "ubuntu"
Výsledkom je samozrejme 0
. Opäť pozor na medzery okolo operátora !=
.
Číselné operátory
Čísla využívajú úplne inú sadu operátorov. Majú svoje, mnemotechnické názvy.
Rovnosť (-eq
)
Rovnosť je -eq
(equal). Napr. zistiť, či skript nemá žiadne dodané parametre z príkazového riadka:
if test $# -eq 0
then
echo "Neboli dodane ziadne parametre!"
exit 1
fi
Nerovnosť (-ne
)
Rovnosť je -ne
(not equal):
POCET=2
test $((100 * 100)) -ne "$POCET"
Väčšie a menšie
Porovnanie sa riadi štyrmi operátormi:
-gt
(greater): >-ge
(greater or equal): >=-lt
(lesser): <-le
(lesser or equal): <=
Zistiť, či skript má vôbec nejaké parametre:
if test "$POCET" -le 0
then
echo "Vyzaduje sa kladne cislo!"
fi
Operátory nad súbormi
Shell dáva k dispozícii paletu operátorov, ktoré chápu reťazce ako cesty k súborom. Čisto telegraficky (tie najdôležitejšie, zvyšné nájdete v dokumentácii POSIX):
-d
: označuje cesta adresár?-e
: existuje súbor?-f
: je to regulárny existujúci súbor?-r
: je to súbor, ktorý má právo na čítanie?-w
: je to súbor, ktorý má právo na zápis?-x
: je to súbor, ktorý má právo na vykonávanie?
Rozličné implementácie shellu dávajú k dispozícii aj ďalšie operátory (napr. pre porovnanie časov vzniku). Tie, ktoré sme uviedli, sú POSIXovo kompatibilné.
Ukážka: môžeme čítať /etc/passwd
?
test -r /etc/passwd
Negácie a skladanie podmienok
POSIXová norma definuje pre negáciu operátor výkričník: !
. Napríklad ekvivalent pre operátor -n
:
test ! -z "$NEDEFINOVANA"
Tradične pozor na syntax: Výkričník musí byť samostatné slovo: nesmie byť nalepený na operátore, pretože inak ho shell nerozpozná.
Pozor tiež pri if
och! V tomto prípade je výkričník vyhodnocovaný príkazom test
:
if [ ! -z "$NEDEFINOVANA" ]
V tejto verzii ho však vyhodnotí sám shell:
if ! [ -z "$NEDEFINOVANA" ]
Príkaz [
skončí s exit code 0 a shell ho za pomoci výkričníka prevráti na nepravdivú hodnotu. Správanie je zhodou okolností rovnaké.
Skladanie podmienok
POSIX síce spomína operátory -a
a -o
, ale len v rozšírenej špecifikácii. Znalci hovoria, že sa im treba zoširoka vyhýbať, pretože s nimi často ide podivné správanie líšiace sa od shellu k shellu. (Základným problémom je fakt, že test
nehovorí, čo sa má stať v prípade 4 a viacerých argumentov.) O čitateľnosti ani nehovoriac, plus sa veľmi často pletú s operátormi &&
a ||
pre skladanie procesov.
Najlepšie je využiť vnorené podmienky.
Ale predsa ukážka: test, či je definovaná premenná CISLO
a či existuje súbor suborX.txt
, kde X je hodnota premennej CISLO
:
[ -n "$CISLO" -a -e "subor$CISLO.txt" ]
test
a jednoriadkové finty
Keďže test
pracuje s návratovými kódmi, veľmi často sa dá syntax if-then
napísať na jeden riadok. Využijú sa pri tom skladania procesov.
Ukážka: zistime, či existuje adresár images
a ak nie, tak ho vytvorme:
if [ ! -d images ]
then
mkdir images
fi
Namiesto toho sa dá použiť skrátené:
test ! -d images && mkdir images
Úplne analogicky:
[ ! -d images ] && mkdir images
Vypísať spustiteľné súbory v aktuálnom adresári môžeme cez:
for F in *
do
[ -x "$F" ] && echo "$F"
done
Alternatívne prostredie
Bash a KornShell umožňujú používať alternatívne prostredie pre testy: tzv. nový test, uvedený v prostredí `[[ .. ]]“ (dve hranaté zátvorky). Rozdiely sú:
- reťazce možno porovnávať aj cez
==
, čo je bližšie srdcu céčkarovmu. - zátvorky na určovanie preferencií netreba escapovať. V klasickom
test
e je nutné používať\(
, resp.\)
. - namiesto podivných operátorov
-a
a-or
máte civilizované&&
a||
. - vo vnútri neprebieha expanzia ciest, ani sekanie textu na shellovské slová. Premenné teda nemusíte uvádzať v úvodzovkách.
Môžeme teda písať:
if [[ -n $CISLO && -e subor$CISLO.txt ]]
then
...
fi