Shellové skriptovanie: zábava s `test`om

S testom 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 testu 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 ifoch! 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 teste 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

Pridaj komentár

Vaša e-mailová adresa nebude zverejnená. Vyžadované polia sú označené *