Ďalšie špeciálne premenné
Parametre príkazového riadka
Minule sa spomínalo, že parametre príkazového riadka sú k dispozícii v premenných 1
…9
. Čo ak chcete iterovať cez všetky parametre a s každým z nich niečo spraviť? Tie sú dostupné v premennej @
.
Hlúpy príklad:
#!/bin/sh
for WORD in "$@"
do
echo $WORD
done
Pamätáme si na for
? Iteruje cez zoznam slov oddelených medzerou. Premenná $@
v úvodzovkách (opakujem, v úvodzovkách) zoberie parametre z príkazového riadka, rozseká ich na jednotlivé slová a každé z nich navyše expanduje.
(Bokom: cyklus for
iteruje v skutočnosti cez slová oddelené prvým znakom premennej IFS
, ale to teraz nemusíme rozoberať.)
Spusťme cez
./iterate.sh on the fourth day of christmas
Vypíše
on
the
fourth
day
of
christmas
Ale! Pozor na úvodzovkovanie! V tomto prípade (v súlade so shellovskou tradíciou) je on the fourth day
považovaný za jedno slovo. Toto:
./iterate.sh "on the fourth day" of "christmas"
Vypíše:
on the fourth day
of
christmas
Mimochodom, vo for
cykle môžeme vynechať klauzulu in...
. Oba zápisy sú ekvivalentné:
for WORD in "$@"
a
for WORD
Ak teda in ...
vynecháme, for
bude prechádzať cez parametre z príkazového riadka.
Pozor na úvodzovky alebo $@
vs "$@"
Dajte si veľký pozor na úvodzovky! Ak ich vynecháte, premenná sa expanduje na slová, kde sa úvodzovky budú ignorovať:
for WORD in $@
pre vstup:
./iterate.sh "on the fourth day" of "christmas"
Vypíše:
on
the
fourth
day
of
christmas
Premenná $*
V krátkosti: smrteľníci ju môžu ignorovať. Vystačíte si s $@
.
Premenná $*
je druhá, mätúca, premenná s parametrami príkazového riadka. Ak ju použijete v úvodzovkách, expanduje na jedno shellovské slovo, kde budú parametre oddelené prvým znakom z premennej IFS
— obvykle medzerou. Cyklus for
potom následne nebude iterovať cez jednotlivé parametre oddelené medzerou, pretože dostane na vstup len jedno shellovské slovo, ktoré vypíše
#!/bin/sh
for WORD in "$*"
do
echo $WORD
done
Spusťme
./iterate.sh "on the fourth day" of christmas
Výsledok:
on the fourth day of christmas
Ak ju použijete bez úvodzoviek, správa sa presne tak ako $@
bez úvodzoviek, čo bolo spomenuté vyššie: zoberie parametre, pričom vôbec nebude brať ohľad na úvodzovky: "on the fourth day"
bude považovať za štyri slová.
Tieto dve premenné sa často pletú, ale ako bolo napísané vyššie: pre typické situácie si úplne vystačíte s $@
. V úvodzovkách, samozrejme.
Parametre príkazového riadka (iný príklad)
Urobme si jednoduchý skript, ktorý dostane parametre na vstup a každý z nich prehodí na proper case, teda prvé písmená každého slova budú veľké:
./propercase.sh driving home for christmas
S výsledkom:
Driving Home For Christmas
Idea bude nasledovná: jednotlivé slová budú parametre príkazového riadka. Z každého slova vezmeme prvé písmeno, to prevedieme na VEĽKÉ, následne zoberieme zvyšok slova, ktorý prevedieme na malé písmená a celé to zlepíme.
Získanie prvého písmena dosiahneme cez head
:
echo traky | head -c1
vráti:
t
Odsekávanie prvého písmena (teda získanie zvyšku slova) získame cez expanziu
WORD=traky
echo ${WORD#?}
vráti:
raky
Modifikátor expanzie #
totiž odsekáva prefix a otáznik je zástupný symbol pre „ľubovoľný znak” (analógia bodky v regulárnych výrazoch).
Preklad veľkých písmen na malé a naopak získame cez tr
.
#!/bin/sh
for WORD
do
INITIAL=$(echo "$WORD" | head -c1 | tr [:lower:] [:upper:])
REST=$(echo ${WORD#?} | tr [:upper:] [:lower:])
printf "%s " $INITIAL$REST
done
echo
Finta s printf
slúži na to, aby sa slová vypísali vedľa seba (echo
by ich totiž nasypalo pod seba). Posledné echo
je estetické: zapíše nový riadok za poslednou položkou.
Zisťovanie návratovej hodnoty: $?
Tradícia UNIXovských programov hovorí, že program môže po dobehnutí vrátiť operačnému systému číselnú návratovú hodnotu, na základe ktorej sa dá následne rozhodnúť, či beh skončil v poriadku, alebo či nastala nejaká chyba. (Je to akýsi praotec výnimiek z objektového programovania.) Nula tradične znamená „dobehol som v poriadku” a akákoľvek iná hodnota indikuje chybu.
Vezmime si taký grep
. Ak spustíte hľadanie a reťazec sa nájde, vráti sa exit code rovný nule. Ak sa reťazec nenájde, exit code bude rovný jednej.
V shelli sa to dá otestovať špeciálnou premennou ?
. Hľa, ukážka:
grep NEEXISTUJUCI_POUZIVATEL /etc/passwd
A následne
echo $?
čo dá výsledok
1
Inak, tento exit code je presne tá hodnota, ktorá sa vráti z funkcie main()
v céčkovských programoch.
Príklad (slovník)
Založme si súbor words.txt
, ktorý bude predstavovať prekladový slovník. Po riadkoch budú dvojice oddelené dvojbodkami:
pes:dog
macka:cat
slon:elephant
vlk:wolf
liska:fox
Skript bude vyzerať nasledovne:
#!/bin/sh
DICTIONARY=words.txt
for WORD
do
RESULT=$(grep "$WORD" "$DICTIONARY")
if [ "$?" == 1 ]
then
echo "Word not found: $WORD"
else
echo ${RESULT##*:}
fi
done
Iterujeme cez parametre príkazového riadka (premenná WORD
) a skúsime grepnúť súbor so slovníkom. Ak sa slovo nenájde, grep vráti jednotku a vypíše hlášku, že slovo sa nenašlo. V opačnom prípade odsekneme z riadka s dvojicou slov všetky znaky po prvú dvojbodku, čím získame preklad.