Erinevus lehekülje "Bash" redaktsioonide vahel
(→Failitestid) |
(→If-elif-else valikulause) |
||
(ei näidata 2 kasutaja 37 vahepealset redaktsiooni) | |||
70. rida: | 70. rida: | ||
NB skriptimiskeeltes, jäetakse 'märkide' vahel olevad muutujad muutmata | NB skriptimiskeeltes, jäetakse 'märkide' vahel olevad muutujad muutmata | ||
+ | |||
+ | Kui muutuja ja tema ümbruse vaheline piir ei ole nö ilmne, siis sobib muutuja esitada kujul ${muutujanimi}, nt | ||
+ | |||
+ | #/bin/bash | ||
+ | arv=2 | ||
+ | echo "teine koht, ehk ${arv}nd place" | ||
===Aritmeetilised tehted=== | ===Aritmeetilised tehted=== | ||
108. rida: | 114. rida: | ||
Näiteks tingimus | Näiteks tingimus | ||
− | [ 5 | + | [ 5 -lt 6 ] |
on tõene kuna "viis on väiksem kuuest". | on tõene kuna "viis on väiksem kuuest". | ||
===If-elif-else valikulause=== | ===If-elif-else valikulause=== | ||
+ | |||
+ | Esimene skript on üsna lihtne. See kontrollib mis väärtus on muutujal $roll ja muudab vastavalt sellele $roll_id muutuja väärtust | ||
+ | |||
+ | <source lang=bash> | ||
+ | if [ "\"$roll\"" == "kasutaja" ]; then | ||
+ | roll_id=1; | ||
+ | elif [ "\"$roll\"" == "poweruser" ]; then | ||
+ | roll_id=2; | ||
+ | elif [ "\"$roll\"" == "adminn" ]; then | ||
+ | roll_id=3; | ||
+ | fi | ||
+ | </source> | ||
Skript genereerib juhusliku arvu vahemikus 0 kuni 32 767 (2^15) ja teatab, milline see on | Skript genereerib juhusliku arvu vahemikus 0 kuni 32 767 (2^15) ja teatab, milline see on | ||
136. rida: | 154. rida: | ||
Näiteks tingimus | Näiteks tingimus | ||
− | [ ! 5 | + | [ ! 5 -lt 6 ] |
on väär kuna "viis on väiksem kuuest", aga kasutatakse loogilist eitust (!). | on väär kuna "viis on väiksem kuuest", aga kasutatakse loogilist eitust (!). | ||
160. rida: | 178. rida: | ||
#!/bin/sh | #!/bin/sh | ||
a=$RANDOM | a=$RANDOM | ||
− | + | if test $a -lt 10000; then | |
echo "Juhuslik arv $a < 10 000" | echo "Juhuslik arv $a < 10 000" | ||
elif test $a -ge 10000 -a $a -lt 20000; then | elif test $a -ge 10000 -a $a -lt 20000; then | ||
203. rida: | 221. rida: | ||
* = võrdne | * = võrdne | ||
* != mittevõrdne | * != mittevõrdne | ||
+ | |||
+ | Lihtne stringide võrdlus oleks selline | ||
+ | |||
+ | <source lang=bash> | ||
+ | if [ "$p_real" = "$p_try" ]; then | ||
+ | echo "Parool klappis!" | ||
+ | else | ||
+ | echo "Parool ei sobi" | ||
+ | fi | ||
+ | </source> | ||
Esitame näite, kus skript ootab vastust küsimusele, "Kes on Kuutõrvaja üks peategelaskujusid?" | Esitame näite, kus skript ootab vastust küsimusele, "Kes on Kuutõrvaja üks peategelaskujusid?" | ||
235. rida: | 263. rida: | ||
Valikut määrav regulaaravaldise stiilis avaldis [a-k]*|[A-K]* tähendab, et klapivad stringid, mis algavad väikese vahemikku a kuni k jääva tähega või samasse vahemikku jääva suure tähega. | Valikut määrav regulaaravaldise stiilis avaldis [a-k]*|[A-K]* tähendab, et klapivad stringid, mis algavad väikese vahemikku a kuni k jääva tähega või samasse vahemikku jääva suure tähega. | ||
+ | |||
+ | Case abil on hea kirjutada näiteks linux süsteemides stardiskripte | ||
+ | |||
+ | <source lang=bash> | ||
+ | #!/bin/bash | ||
+ | case $1 in | ||
+ | start) /bin/su <username> /bin/startup.sh ;; | ||
+ | stop) /bin/su <username> /bin/shutdown.sh ;; | ||
+ | restart) | ||
+ | /bin/su <username> /bin/shutdown.sh | ||
+ | /bin/su <username> /bin/startup.sh | ||
+ | ;; | ||
+ | esac | ||
+ | exit 0 | ||
+ | </source> | ||
===Select valikulause=== | ===Select valikulause=== | ||
324. rida: | 367. rida: | ||
echo "Lines: $counter" | echo "Lines: $counter" | ||
</source> | </source> | ||
+ | |||
+ | Muide kõike seda võib teha ka ühe real, nt loeme nimetused.txt failist failide nimed ja tekitame need kettale | ||
+ | |||
+ | # cat nimetused.txt | while read a; do touch $a & done | ||
====Until korduslause==== | ====Until korduslause==== | ||
389. rida: | 436. rida: | ||
* ! - "!$" viimati tagaplaanil käivitatud programmi nimi | * ! - "!$" viimati tagaplaanil käivitatud programmi nimi | ||
* 0 - "$0" skripti enda nimi | * 0 - "$0" skripti enda nimi | ||
+ | |||
+ | "$@" on kõige õigem ja puhtam meetod argumentide edasikandmiseks, säilitatakse kõik tühikud jm metamärgid. Ja tegu ei ole mitte bashismi, vaid klassikalise Bourne shelli omadusega. | ||
+ | |||
+ | Alternatiivid -- $@, $*, "$*" -- on eri kõrvalmõjudega. Mdx mõnel juhul on abiks ka kontruktsioon "saba $@ sarved" nSeejuures $@ ei käitu nagu tavalised muutujad, kui topeltjutumärkide vahele satuvad, vaid seal laiendatakse seda justkui: "$1" "$2" - ehk siis kui iga argument oleks eraldi topeltjutumärkide vahel antud. | ||
+ | |||
+ | Natuke mõeldes leiab sellisele käitumisele ka kasutusjuhu - kui ühe argumendi sees on tühikud: | ||
+ | |||
+ | <source lang=bash> | ||
+ | #!/bin/bash | ||
+ | |||
+ | f1(){ | ||
+ | for arg in "$@"; do echo "arg: $arg";done | ||
+ | } | ||
+ | |||
+ | f2(){ | ||
+ | args=$@ | ||
+ | for arg in $args; do echo "arg: $arg"; done | ||
+ | } | ||
+ | |||
+ | echo "F1:" | ||
+ | f1 a b c "d ja e" | ||
+ | echo "F2:" | ||
+ | f2 a b c "d ja e" | ||
+ | </source> | ||
+ | |||
+ | Tulemus: | ||
+ | % bash test.sh | ||
+ | F1: | ||
+ | arg: a | ||
+ | arg: b | ||
+ | arg: c | ||
+ | arg: d ja e | ||
+ | F2: | ||
+ | arg: a | ||
+ | arg: b | ||
+ | arg: c | ||
+ | arg: d | ||
+ | arg: ja | ||
+ | arg: e | ||
+ | |||
+ | Veel üks praktiline näide, järgnev skript käivitab kõik argumendid ükshaaval ettemääratud nodes | ||
+ | |||
+ | <source lang=bash> | ||
+ | #!/bin/bash | ||
+ | for osd in "$@"; do | ||
+ | ssh -q $node argument=$argument bash <<EOF | ||
+ | $osd | ||
+ | EOF | ||
+ | done | ||
+ | </source> | ||
+ | |||
+ | Tasub tähele panna ssh käsus $node argument=$argument konstruktsiooni, mis annab muutuja edasi kaugel olevale serverile | ||
===Failitestid=== | ===Failitestid=== | ||
418. rida: | 517. rida: | ||
done | done | ||
</source> | </source> | ||
+ | |||
+ | Kasutatavad võtmed on järgnevad: | ||
*-d Kas tegu kataloogiga | *-d Kas tegu kataloogiga | ||
429. rida: | 530. rida: | ||
===Käskude käivitamine skripti sees=== | ===Käskude käivitamine skripti sees=== | ||
− | Oletame, et soovime saada skriptis käsu: uname -a väjundi | + | Aegajalt tuleb ette, et on vaja käivitada mingi käsk ning selle tulemit |
+ | skripti sees töödelda. Oletame, et soovime saada skriptis käsu: uname -a väjundi | ||
Selleks olemas kolm võimalust, esiteks kasutades eraldajaid | Selleks olemas kolm võimalust, esiteks kasutades eraldajaid | ||
439. rida: | 541. rida: | ||
echo $(uname -a) | echo $(uname -a) | ||
− | Käsu tulemi saab kergelt edastada | + | Käsu tulemi saab kergelt edastada muutujale: |
OS=$(uname -a) | OS=$(uname -a) | ||
453. rida: | 555. rida: | ||
kolmas rida | kolmas rida | ||
EOT | EOT | ||
+ | |||
+ | NB! EOT või EOF peab olema rea alguses, kui on taandega, pannakse kuni faili lõpuni kõik stringi sisse. | ||
Toome näite CGI valdkonnast | Toome näite CGI valdkonnast | ||
532. rida: | 636. rida: | ||
kas_korras | kas_korras | ||
+ | |||
+ | Võimalus on ka genereerida funktsiooniga paroole: | ||
+ | |||
+ | genpasswd() { | ||
+ | local l=$1 | ||
+ | [ "$l" == "" ] && l=16 | ||
+ | tr -dc A-Za-z0-9_ < /dev/urandom | head -c ${l} | xargs | ||
+ | } | ||
+ | |||
+ | Ja kasutamiseksd | ||
+ | |||
+ | genpasswd 8 | ||
+ | |||
+ | ===Käsurea parameetrid=== | ||
+ | |||
+ | Skripti järgi antud parameetrid omistatakse muutujatele $1 $2 $3 jne | ||
+ | |||
+ | Näiteks soovime anda sedasi parameetreid: | ||
+ | |||
+ | $ ./skript eesnimi perenimi vanus | ||
+ | |||
+ | Skript mis need väljastab võiks olla selline | ||
+ | |||
+ | #!/bin/bash | ||
+ | echo $1 | ||
+ | echo $2 | ||
+ | echo $3 | ||
===Lock faili kasutamine skriptis=== | ===Lock faili kasutamine skriptis=== | ||
547. rida: | 678. rida: | ||
return | return | ||
else | else | ||
− | lockf -t 0 /var/run/skript.lock | + | lockf -t 0 /var/run/skript.lock sleep 1000 |
fi | fi | ||
</source> | </source> | ||
561. rida: | 692. rida: | ||
eelmine programm ikka veel toimib. | eelmine programm ikka veel toimib. | ||
− | Lockfaili võib muidugi käsu lockf puudumisel tekitada ka lihtsalt touch käsuga ja hiljem eemaldada | + | Lockfaili võib muidugi käsu lockf puudumisel tekitada ka lihtsalt mkdir-touch käsuga ja hiljem eemaldada, näiteks |
+ | |||
+ | if [ -f /var/run/$1.lock ]; then | ||
+ | echo "$1 eelmine mirror ikka veel töötab." | ||
+ | return | ||
+ | else | ||
+ | if mkdir /run/$1.lock; then | ||
+ | rsync .... | ||
+ | rmdir /run/$1.lock | ||
+ | fi | ||
===Bash ja internet=== | ===Bash ja internet=== | ||
624. rida: | 764. rida: | ||
debug "VASTUS: $VASTUS"$ | debug "VASTUS: $VASTUS"$ | ||
</source> | </source> | ||
+ | |||
+ | ===Sõnastiku kasutamine=== | ||
+ | |||
+ | Bash v. 4 võimaldab kasutada sõnastikku (ingl. k. associative array). Nt olgu failisüsteemis sellised failid | ||
+ | |||
+ | $ pwd | ||
+ | /home/priit/skriptid | ||
+ | $ find . -type f | ||
+ | ./sql/konvert_ee/konvert_20120515.sql | ||
+ | ./sql/konvert_ee/konvert_20120515a.sql | ||
+ | ./sql/konvert_ee/konvert_20120515b.sql | ||
+ | ./sql/konvert_20120520a.sql | ||
+ | ./sql/konvert_20120505.sql | ||
+ | ./sql/konvert_20120520b.sql | ||
+ | ./sql/konvert_20120520.sql | ||
+ | |||
+ | ning eesmärk käivitada, sõltumata sellest, millises kataloogis üks või teine skript asub, nad kronoloogilises järjekorras (kasutades seejuures faili nimes esinevat YYYYMMDD osa). | ||
+ | |||
+ | $ cat jarjesta-ja-kaivita.sh | ||
+ | #!/bin/bash | ||
+ | declare -A sql_kataloog | ||
+ | |||
+ | for i in `cd /home/priit/skriptid; find sql -type f | xargs`; do | ||
+ | j=`echo $i | sed 's/sql\/konvert_ee\///' | sed 's/sql\/konvert_lv\///' | sed 's/sql\///'` | ||
+ | sql_kataloog[$j]=$i | ||
+ | done | ||
+ | |||
+ | for key in `export LANG=C; echo ${!sql_kataloog[@]} | tr " " "\n" | sort | tr "\n" " "` ; do | ||
+ | echo psql ${sql_kataloog[$key]} | ||
+ | done | ||
+ | |||
+ | kus | ||
+ | |||
+ | * declare -A sql_kataloog - kirjeldab sõnastik tüüpi muutuja | ||
+ | * find ja xargs abil moodustatakse kataloogiteedega failinimede nimekiri | ||
+ | * sql_kataloog[$j]=$i - omistatakse sõnastiku võtmele (nt konvert_20120515b.sql) vastav väärtus (nt sql/konvert_ee/konvert_20120515b.sql) | ||
+ | * export LANG=C abil saab mõjutada järjestust | ||
+ | * echo ... tr ... sort ... tr abil järjestatakse sõnastik võtmete järjekorras | ||
+ | |||
+ | Kävitamisel vajastatakse | ||
+ | |||
+ | $ ./jarjesta-ja-kaivita.sh | ||
+ | psql sql/konvert_20120505.sql | ||
+ | psql sql/konvert_ee/konvert_20120515a.sql | ||
+ | psql sql/konvert_ee/konvert_20120515b.sql | ||
+ | psql sql/konvert_ee/konvert_20120515.sql | ||
+ | psql sql/konvert_20120520a.sql | ||
+ | psql sql/konvert_20120520b.sql | ||
+ | psql sql/konvert_20120520.sql | ||
+ | |||
+ | ===Tingimuse kasutamine programmi väljundkoodiga=== | ||
+ | |||
+ | If tingimusega saab kasutada lisaks test vms konstruktsioonidele ka programmide väljundkoode (ingl. k. exit code, exit status) arvestades asjaolu, et reeglina on väljundkood programmi töö ilma veata lõppemisel 0 ning igal muul juhul > 0. Nt sobiks sellise skripti abil kustutada mingi rakenduse töö käigus tekkivaid zip faile /tmp kataloogist | ||
+ | |||
+ | for i in $(find /tmp -maxdepth 1 -mtime +2 -type f | xargs); do | ||
+ | if $(unzip -qt $i 1>/dev/null 2>&1) ; then | ||
+ | rm $i | ||
+ | fi | ||
+ | done | ||
+ | |||
+ | ===Sõnedega töötamine=== | ||
+ | |||
+ | Sõnest (ingl. k. string) saab eralda osa selliselt, viienda positsiooni järelt lõpuni | ||
+ | |||
+ | $ sone="tuulevaikus" | ||
+ | $ echo ${sone:5} | ||
+ | vaikus | ||
+ | |||
+ | Või expr abil | ||
+ | |||
+ | $ sone="tuulevaikus" | ||
+ | $ echo `expr substr $sone 6 7` | ||
+ | vaikus | ||
+ | |||
+ | Kasulikud lisamaterjalid | ||
+ | |||
+ | * http://tldp.org/LDP/abs/html/string-manipulation.html | ||
+ | |||
+ | ===Tühikuid sisaldavate failinimedega töötamine=== | ||
+ | |||
+ | Kui faili või katalooginimedes esinevad tühikud, siis selline konstruktsioon ei tööta | ||
+ | |||
+ | $ for i in *; do du -sk $i; done | ||
+ | |||
+ | aga töötab selline find + while kasutamine | ||
+ | |||
+ | $ find . -type d ! -name . | while read nimi; do du -sk "$nimi"; done | ||
+ | 8 ./Teater Vanemuine | ||
+ | 8 ./Kala maja | ||
+ | 8 ./Supi linn | ||
+ | |||
+ | ===Skriptisiseste teadete ja veateadetega tegelemine=== | ||
+ | |||
+ | Bash shelli stdout ja stderr | ||
+ | |||
+ | 0 Stdin - kasutatakse info programmi sisestamiseks | ||
+ | 1 stdout - kasutatakse info kirjutamiseks ekraanile | ||
+ | 2 stderr - kasutatakse error teadete väljutamiseks | ||
+ | |||
+ | Näiteks veateadete faili logimine toimib nii | ||
+ | |||
+ | $ program-name 2> error.log | ||
+ | |||
+ | Nii veatedete kui niisama programmi sisteste teadete faili suunamiseks | ||
+ | |||
+ | $ command-name &>file | ||
+ | |||
+ | Selleks, et suunatada stderr ümber stdouti | ||
+ | |||
+ | $ command-name 2>&1 | ||
+ | |||
+ | Programmi väljundi saab saata /dev/nulli lihtsa käsuga > /dev/null kahjuks ei tööta | ||
+ | see programmidega, mis väljutavad ohtralt standard error 2 teateid. Selleks tuleb kasutada järgnevat süntaksit | ||
+ | |||
+ | $ command > /dev/null 2>&1 | ||
+ | |||
+ | ===Suvaliste numbrite 0-10 genereerimine=== | ||
+ | |||
+ | Mitte seotud küll bashi sisemise struktuuri vaid hulga unixi/linuxi käskude koos kasutamisega aga tulem | ||
+ | kulub sageli bashis ära. | ||
+ | |||
+ | grep -m1 -ao '[0-9]' /dev/urandom | sed s/0/10/ | head -n1 | ||
+ | |||
+ | ===Mõned kasulikud skriptide näited=== | ||
+ | |||
+ | [[Mirrordamise skript]] Sobilik näiteks avaliku FTP serveri loomiseks. | ||
+ | |||
+ | [[Skript posti quota kontrollimiseks mboxidel]] |
Viimane redaktsioon: 14. mai 2019, kell 15:17
Sisukord
- 1 Bash kooriku skript
- 2 Skripti kirjutamine ja käivitamine
- 3 Skript käivitatakse käsurealt
- 4 Muutuja ja väärtuse omistamine
- 5 Aritmeetilised tehted
- 6 Tingimused ja valikulause
- 7 If-elif-else valikulause
- 8 Case valikulause
- 9 Select valikulause
- 10 Korduslaused
- 11 Sisend, väljund ja käsurea argumendid
- 12 Failitestid
- 13 Käskude käivitamine skripti sees
- 14 Sisestus märgini
- 15 Funktsioonid
- 16 Käsurea parameetrid
- 17 Lock faili kasutamine skriptis
- 18 Bash ja internet
- 19 Subshelli kasutamine
- 20 Skriptide hingeelust
- 21 Sõnastiku kasutamine
- 22 Tingimuse kasutamine programmi väljundkoodiga
- 23 Sõnedega töötamine
- 24 Tühikuid sisaldavate failinimedega töötamine
- 25 Skriptisiseste teadete ja veateadetega tegelemine
- 26 Suvaliste numbrite 0-10 genereerimine
- 27 Mõned kasulikud skriptide näited
Bash kooriku skript
Kooriku skript on tekstifail, millesse on kirjutatud üksteise järele programmi nimed või kooriku sisekäsud. Lisaks saab kasutada programmeerimisele iseloomulikke konstruktsioone, nagu tingimus, kordus- ja valiklause jne. Koorik on interpreteeritav keel.
Paljud süsteemi utiliidid on kooriku skriptid.
Skripti kirjutamine ja käivitamine
Kooriku skript kirjutatakse tekstiredaktoris, kusjuures failil peab olema lugemis- ja käivitamisõigus.
Näiteks toome skripti, mis kirjutab ekraanile "Näe, poolkuu".
#!/bin/sh
echo "Näe, poolkuu"
Selgituseks märgime, et
- #!/bin/sh näitab interpretaatori nime
- echo on sisekäsk, mis väljastab ekraanile oma argumendi
Skript käivitatakse käsurealt
Esmalt tuleb skript teha käivitatavaks öeldes
$ chmod 0755 skript.sh
ja käivitada
$ ./skript.sh
Heaks kombeks on skripti nimi lõpetada mõnetähelise kombinatsiooniga, mis viitab interpretaatorile - '.sh'.
Skripti käivitamisel käivitatakse uus koorik, milles skripti käsud täidetakse.
Muutuja ja väärtuse omistamine
Muutuja nimi peab algama tähe või alakriipsuga, kusjuures võib sisaldada neid ja ka numbreid. Muutuja tüüpi pole tarvis deklareerida.
Muutujale väärtuse omistamisel märgitakse teda vaid nimega (a_1), kuid talle viidates peab alustama muutuja nime dollar ($a_1). Näites omistatakse võrdusmärgi abil muutujale väärtus ja kasutatakse seda
#!/bin/sh
a_1=5
b_1=$a_1
c_1=Tere
echo $a_1
echo $b_1
echo $c_1
Tühikute olemasolu ja puudumine on oluline.
Kui muutujale väärtust omistades on vaja vältida metasümbolite erilist käsitlust, siis tuleb avaldis kirjutada ülakomade vahele, näiteks
#!/bin/sh
echo 'Ei asenda keskkonnamuutujat $OSTYPE tema väärtusega'
Kui on tarvis, et keskkonnamuutujad asenduksid oma väärtustega ning toimuks muutuja väärtustamine, siis kasutatakse jutumärke, näiteks
#!/bin/sh
echo "Keskkonnamuutujate asemele tekivad nende väärtused: $OSTYPE"
echo "Muutujad väärtustatakse: $(date)"
echo "Käsud väärtustatakse: `date`"
echo "Aritmeetiline väärtustamine: 11 + 11 = $((11+11))"
NB skriptimiskeeltes, jäetakse 'märkide' vahel olevad muutujad muutmata
Kui muutuja ja tema ümbruse vaheline piir ei ole nö ilmne, siis sobib muutuja esitada kujul ${muutujanimi}, nt
#/bin/bash arv=2 echo "teine koht, ehk ${arv}nd place"
Aritmeetilised tehted
Esitame näited aritmeetiliste tehete kohta
- "+, -" - liitmine ja lahutamine
- "*, /, %" - korrutamine, jagamine ja jääk
- "<<, >>" - bitinihe
#!/bin/sh
a=255
b=1
c=5
d=50
a_miinus_c=$(($a - $b))
a_jaak_d=$(($a % $d))
a_bitinihe_paremale_b=$(($a >> $b))
echo "$a - $b = $a_miinus_c"
echo "$a % $d = $a_jaak_d"
echo "$a >> $b = $a_bitinihe_paremale_b"
Tingimused ja valikulause
Valikulause võimaldab vastavalt seatud tingimustele programmi edasist käiku suunata.
Arvulisi suurusi võrreldakse järgmiste loogiliste operaatoritega
- -eq - võrdne (ingl. k. equal)
- -ne - mittevõrdne (ingl. k. not equal)
- -lt - väiksem (ingl. k. less than)
- -le - väiksemvõrdne (ingl. k. less equal)
- -gt - suurem (ingl. k. greater than)
- -ge - suuremvõrdne (ingl. k. greater equal)
Näiteks tingimus
[ 5 -lt 6 ]
on tõene kuna "viis on väiksem kuuest".
If-elif-else valikulause
Esimene skript on üsna lihtne. See kontrollib mis väärtus on muutujal $roll ja muudab vastavalt sellele $roll_id muutuja väärtust
if [ "\"$roll\"" == "kasutaja" ]; then
roll_id=1;
elif [ "\"$roll\"" == "poweruser" ]; then
roll_id=2;
elif [ "\"$roll\"" == "adminn" ]; then
roll_id=3;
fi
Skript genereerib juhusliku arvu vahemikus 0 kuni 32 767 (2^15) ja teatab, milline see on
#!/bin/sh
a=$RANDOM
if [ $a -lt 10000 ]; then
echo "Juhuslik arv $a < 10 000"
elif [ $a -ge 10000 -a $a -lt 20000 ]; then
echo "Juhuslik arv on 10 000 <= $a < 20 000"
else [ $a -ge 20000 -a $a -lt 32767 ]
echo "Juhuslik arv on 20 000 <= $a < 32767"
fi
Näites esitatakse tingimused, kusjuures
- -a (AND) nõuab mõlema tingimuse samaaegset täidetust
- -o (OR) väljendab, et täidetud võib olla üks või teine või mõlemad.
- ! (NOT) alustades tingimust hüüumärgiga märgitakse eitust
Näiteks tingimus
[ ! 5 -lt 6 ]
on väär kuna "viis on väiksem kuuest", aga kasutatakse loogilist eitust (!).
Kantsulgude asemel võib tingimuse esitamisel kasutada suvalist programmi. Sel juhul tõlgendatakse programmi lõppkoodi väärtust tõeväärtusena, so 0 on tõene ja muu väär. Näites saadab õppejõud igale praktikumist puudujale kirja, milles ta vabandab, et viib õppetööd läbi ilma tegelase osavõtuta
#!/bin/sh
for i in priit miima peeter mart liibu
do
if ! who | grep $i ; then
echo -e "Subject: Ma vabandan, et Teid polnud kohal\n\n." | \
/usr/sbin/sendmail $i
fi
done
Nagu ikka, peab rida jätkav kaigas olema viimane sümbol real.
Tihti kasutatakse tingimuste esitamisel spetsiaalset sisekäsku test. Esitame näite selle käsu kasutamisest
#!/bin/sh
a=$RANDOM
if test $a -lt 10000; then
echo "Juhuslik arv $a < 10 000"
elif test $a -ge 10000 -a $a -lt 20000; then
echo "Juhuslik arv on 10 000 <= $a < 20 000"
else test $a -ge 20000 -a $a -lt 32767
echo "Juhuslik arv on 20 000 <= $a < 32767"
fi
If-else tingimust saab esitada ka && (AND) ja || (OR) abil
#!/bin/sh
a=$RANDOM
(test $a -lt 15000 && echo "$a < 15 000" ) || echo "$a >= 15 000"
&& -le järgnev käsk täidetakse, kui eelnenud käsu lõppkood oli null (tõene). || -le järgnev käsk täidetakse, kui eelnenud käsu lõppkood oli üks (väär).
Loogiliste tehetega mängimiseks on otstarbekas kasutada spetsiaalseid programme true ja false, mis ei tee muud, kui tagastavad vastava lõppkoodi
bash~$ (true && echo "õige" ) || echo "väär"
õige
bash~$ (false && echo "õige" ) || echo "väär"
väär
Tavaline on skriptides kontrollida mingite muutujate seadistust, näiteks kontrollime kas ssl kataloog on seadistatud
if [ "$MOD_SSL_DIR" = "" ]
then
echo "MOD_SSL_DIR seadmata"
exit 1
fi
Leksikograafilisi tingimusi esitatakse järgmiste loogiliste operaatorite abil
- = võrdne
- != mittevõrdne
Lihtne stringide võrdlus oleks selline
if [ "$p_real" = "$p_try" ]; then
echo "Parool klappis!"
else
echo "Parool ei sobi"
fi
Esitame näite, kus skript ootab vastust küsimusele, "Kes on Kuutõrvaja üks peategelaskujusid?"
#!/bin/sh
echo "Kes on Kuutõrvaja üks peategelaskujusid?\n"
read vastus
if [ $vastus = "Priit" ]; then
echo "Õige"
else
echo "Vale"
fi
Rida 'read vastus' ootab klaviatuurilt sisestust ning omistab selle muutuja $vastus väärtuseks.
Case valikulause
Case valik võimaldab valida mitme tegevuse vahel. Näide teatab, kas sisestatud sõna algustäht oli vahemikust A-K, L-Z või midagi muud
#!/bin/sh
echo "Sisestage klaviatuurilt sõna:"
read a
case $a in
[a-k]*|[A-K]*) echo "Sisestatud sõna algab tähega vahemikust A kuni K";;
[l-z]*|[L-Z]*) echo "Sisestatud sõna algab tähega vahemikust L kuni Z";;
*) echo "Midagi muud";;
esac
Valikut määrav regulaaravaldise stiilis avaldis [a-k]*|[A-K]* tähendab, et klapivad stringid, mis algavad väikese vahemikku a kuni k jääva tähega või samasse vahemikku jääva suure tähega.
Case abil on hea kirjutada näiteks linux süsteemides stardiskripte
#!/bin/bash
case $1 in
start) /bin/su <username> /bin/startup.sh ;;
stop) /bin/su <username> /bin/shutdown.sh ;;
restart)
/bin/su <username> /bin/shutdown.sh
/bin/su <username> /bin/startup.sh
;;
esac
exit 0
Select valikulause
See on väga sarnane Case valikule olles interaktiivsem
#!/bin/sh
select i in "Tartu" "Valga" "Paide" "Ahja" "Ots"
do
case $i in
Tartu) echo "Tartu" ;;
Valga) echo "Valga" ;;
Paide) echo "Paide" ;;
Ahja) echo "Ahja" ;;
Ots) exit ;;
*) echo "midagi muud" ;;
esac
done
Korduslaused
Kordus võimaldab teatud arv kordi korrata tegevust.
For korduslause
For korduses seatakse tavaliselt otseselt paika korduste arv. Toome näite
#!/bin/sh
a="Tartu Elva Puhja Polva"
for i in $a
do
echo $i
done
Iga järgmise kordusega omandab muutuja $i uue väärtuse nimekirjast, milleks on muutuja $a tühikuga eraldatud alamstringid. Muutujale $a võib väärtust omistada ka kasutades käsu väärtustamist, näiteks jätame muutuja $a enda kasutamata
#!/bin/sh
for i in `ls r*`
do
echo $i
done
Näites kuvatakse kõik r tähega algavad failinimed.
Näide: Lisame kõigile failidele uue eesliidese
Failid: aaa.ee asd.ee uuu.aa
$ for i in *; do mv "$i" "ehee-`basename $i`"; done
Tulemus: ehee-aaa.ee ehee-asd.ee ehee-uuu.aa
While korduslause
While kordust korratakse kuni tingimus on tõene. Näites sooritatakse kordus kuni muutuja $a on väiksem kümnest
#!/bin/sh
a=0
while [ $a -lt 10 ]
do
echo $a
a=$(($a+1))
done
Või siis saab seda kasutada failist kõikide ridade välja võtmiseks ning töötlemiseks
while read inputline
do
echo $inputline
done < /tmp/viiruslogi.txt
exit 0
Kolmas näide kuidas while abil lugeda kokku passwd faili ridade arv.
counter=0
while read; do ((counter++)); done </etc/passwd
echo "Lines: $counter"
Muide kõike seda võib teha ka ühe real, nt loeme nimetused.txt failist failide nimed ja tekitame need kettale
# cat nimetused.txt | while read a; do touch $a & done
Until korduslause
Kordust sooritatakse kuni tingimus saab tõeseks.
#!/bin/sh
a=20
while [ $a -lt 10 ]
do
echo $a
a=$(($a-1))
done
Kordusest väljumine
Kasutades korduse sees lisatingimust, on võimalik kordusest väljuda käsuga exit. Skripti täitmine jätkub kordusele järgnevast käsust. Näites sooritatakse kordus kuni muutuja $i saab võrdseks stringiga "teie"
#!/bin/sh
a="mina sina tema meie teie nemad"
for i in $a
do
if test $i = "teie"; then
exit
else
echo $i
fi
echo "Skripti lõpp"
done
Sisend, väljund ja käsurea argumendid
Skripti sisendi vastuvõtmist korraldab käsk read. Loeme näites sisendit kuni andmete lõppemiseni ning trükime välja vastavad suured tähed.
#!/bin/sh
while read a
do
echo $a | tr "a-z" "A-Z"
done
Suuname programmi df väljundi skripti sisendisse
bash~$ df | skript.sh
Skripti väljund tekitatakse tavaliselt käsuga echo.
Skripti käivitamisel saab anda ka argumente, kusjuures nende väärtused on skriptis muutujates $1, $2 jne.
#!/bin/sh echo $1 $2 $3
Lisaks on olulised sellised muutujad
- * - "$*" väärtustub stringiks, kus on kõik argumendid tühikutega eraldatud
- @ - "$@" väärtustub mitmeks stringiks, mis on vastavalt käsurea argumendid
- # - "$#" käsurea argumentide arv
- ? - "$?" eelmise esiplaanil käivitatud programmi väljundkood
- $ - "$$" skripti enda PID
- ! - "!$" viimati tagaplaanil käivitatud programmi nimi
- 0 - "$0" skripti enda nimi
"$@" on kõige õigem ja puhtam meetod argumentide edasikandmiseks, säilitatakse kõik tühikud jm metamärgid. Ja tegu ei ole mitte bashismi, vaid klassikalise Bourne shelli omadusega.
Alternatiivid -- $@, $*, "$*" -- on eri kõrvalmõjudega. Mdx mõnel juhul on abiks ka kontruktsioon "saba $@ sarved" nSeejuures $@ ei käitu nagu tavalised muutujad, kui topeltjutumärkide vahele satuvad, vaid seal laiendatakse seda justkui: "$1" "$2" - ehk siis kui iga argument oleks eraldi topeltjutumärkide vahel antud.
Natuke mõeldes leiab sellisele käitumisele ka kasutusjuhu - kui ühe argumendi sees on tühikud:
#!/bin/bash
f1(){
for arg in "$@"; do echo "arg: $arg";done
}
f2(){
args=$@
for arg in $args; do echo "arg: $arg"; done
}
echo "F1:"
f1 a b c "d ja e"
echo "F2:"
f2 a b c "d ja e"
Tulemus:
% bash test.sh F1: arg: a arg: b arg: c arg: d ja e F2: arg: a arg: b arg: c arg: d arg: ja arg: e
Veel üks praktiline näide, järgnev skript käivitab kõik argumendid ükshaaval ettemääratud nodes
#!/bin/bash
for osd in "$@"; do
ssh -q $node argument=$argument bash <<EOF
$osd
EOF
done
Tasub tähele panna ssh käsus $node argument=$argument konstruktsiooni, mis annab muutuja edasi kaugel olevale serverile
Failitestid
Sisekäsk test võimaldab kontrollida faili tüüpi. Näiteks eristame kataloogis olevad lingid, tavalised faili ja kataloogid
Näiteks
if [ -r test.jpg ]
then
echo "Fail on loetav"
fi
Keerukam näide:
#!/bin/bash
for i in `ls -a`
do
if test -f $i; then
echo $i: fail
elif test -L $i; then
echo $i: link
elif test -d $i; then
echo $i: kataloog
fi
done
Kasutatavad võtmed on järgnevad:
- -d Kas tegu kataloogiga
- -f Kas tegu failiga
- -r Kas fail loetav
- -s Kas fail nullist erineva suurusega
- -w Kas fail kirjutatav
- -x Kas fail käivitatav
- -L Kas tegu lingiga
Käskude käivitamine skripti sees
Aegajalt tuleb ette, et on vaja käivitada mingi käsk ning selle tulemit skripti sees töödelda. Oletame, et soovime saada skriptis käsu: uname -a väjundi
Selleks olemas kolm võimalust, esiteks kasutades eraldajaid
echo `uname -a`
Või
echo $(uname -a)
Käsu tulemi saab kergelt edastada muutujale:
OS=$(uname -a) echo $OS
Sisestus märgini
Märgini sisestamine võimaldab vältida mitmete järjestikuste käskude echo kasutamist.
cat >> /home/kasutaja/fail <<EOT esimene rida teine rida kolmas rida EOT
NB! EOT või EOF peab olema rea alguses, kui on taandega, pannakse kuni faili lõpuni kõik stringi sisse.
Toome näite CGI valdkonnast
#!/bin/bash
echo -e "Content-type: text/html\n\n"
a=`df`
cat <<mark
<HTML><BODY>
<p>Tere, masina failisüsteemiga on sellised lood:<p>
<pre>
$a
</pre>
<pre>
$(hostname -f)
$(date)
</pre>
</BODY></HTML>
mark
Kusjuures, kui 'cat <<mark' rida asendada 'cat <<\mark', siis muutujaid ei asendata ega väärtustata.
Funktsioonid
Tihti esinevaid järgnevusi on mõistlik kirjeldada kord funktsioonina ning hiljem kasutada nende poole pöördumiseks seda funktsiooni. Näiteks loome funktsiooni, mis paneb teksti < pre > ja < /pre > märkide vahele.
#!/bin/sh
function pre () {
echo -e "<pre>$1</pre>"
}
echo -e "Content-type: text/html\n\n<HTML ><BODY>"
pre "`df`"
pre "`uptime`"
echo "</BODY></HTML>"
Funktsioonis kirjeldatu käivitamiseks ei tekitata uut koorikut. Argumente saab kasutada sarnaselt skriptile endale.
Teise näitena küsime kinnitust kasutajalt mingi tegevuse toestamise kohta
kinnitus(){
echo
echo
echo -n "$1 (y/n) [n] "
read VASTUS
if [ "$VASTUS" != "y" ]
then
exit
fi
}
Kasutamine järgnev
kinnitus "installime vajalikud komponendid ?"
Üks shelliskriptis suisa häda vajalik funktsioon oleks kontrollida kas eelmine käsk on väljastanud mingi veateate ehk siis lõpetanud enda tegevuse ebaviisakalt
kas_korras(){
RET=$?
if [ "$RET" != '0' ]
then
echo
echo "eelmine käsk väljastas: $RET"
exit $RET
fi
}
Ning seejärel võib lisada näiteks make käsu järele kontrollfunktskiooni
kas_korras
Võimalus on ka genereerida funktsiooniga paroole:
genpasswd() { local l=$1 [ "$l" == "" ] && l=16 tr -dc A-Za-z0-9_ < /dev/urandom | head -c ${l} | xargs }
Ja kasutamiseksd
genpasswd 8
Käsurea parameetrid
Skripti järgi antud parameetrid omistatakse muutujatele $1 $2 $3 jne
Näiteks soovime anda sedasi parameetreid:
$ ./skript eesnimi perenimi vanus
Skript mis need väljastab võiks olla selline
#!/bin/bash echo $1 echo $2 echo $3
Lock faili kasutamine skriptis
Vahel on vajalik saavutada olukord kus skripti selle töötamise ajal uuesti enam käivitada ei saa, siin tuleb appi lockf abil tekitatav /var/run/skript.lock nimeline fail
skripti idee lihtsalt tuhat sekundit passida
#!/bin/sh
if [ -f /var/run/skript.lock ]; then
echo "eelmine programm ikka veel toimib."
return
else
lockf -t 0 /var/run/skript.lock sleep 1000
fi
Paneme skripti toimima taustal
# ./skript.sh & [1] 80562
proovime veelkord startida
# ./skript.sh eelmine programm ikka veel toimib.
Lockfaili võib muidugi käsu lockf puudumisel tekitada ka lihtsalt mkdir-touch käsuga ja hiljem eemaldada, näiteks
if [ -f /var/run/$1.lock ]; then echo "$1 eelmine mirror ikka veel töötab." return else if mkdir /run/$1.lock; then rsync .... rmdir /run/$1.lock fi
Bash ja internet
Bash võimaldab tegeleda ka võrgu socketiga. Viimaste kaudu on võimalik avada võrguühendus mõne pordiga ja vahetada sellega infot.
Socketi asukohaks Linuxis /dev/tcp/SERVER/PORT
Näiteks saadame emaili serveri zoo.tartu.ee 25 pordile HELO käsu
#avame socketi
exec 3<>/dev/tcp/zoo.edu.ee/25
# saadame HELO käsu
echo -e "HELO mail.edu.ee" >&3
# loeme tulemust
while read line <&3
do
echo -n $line >&1
done
# saadame QUIT käsu
echo -e "QUIT" >&3
# sulgeme sisendi
exec 3<&-
# sulgeme väljundi
exec 3>&-
Subshelli kasutamine
Sulgude vahel esitatu töötab omaette keskkonnas, mille kohta öeldakse, et ta moodustab subshelli. Nt sobib subshelli abil suunata mitme käsu väljundit koos edasi
$ (echo tere1; echo tere2) | tr a-z A-Z
TERE1
TERE2
Skriptide hingeelust
Shelli skriptidele saadetakse SIGHUP (võibolla veel midagi), kui ühendus katkeb ja selle peale lõpetab skript tavaliselt töö (ja üritab oma lapsed kah ära tappa).
Testimisel piisas, kui SIGHUP kinni püüda ja ignoreerida. Lõpus skript, mis seda demob.
#!/usr/local/bin/bash$
$
trap trhup HUP$
trhup(){$
debug "SIGHUP detected.. interesting"$
}$
$
debug(){$
echo "`date` $1" >> tulemus.txt$
}$
$
debug "ALGUS"$
echo -n "Katsetuse testimine. Toksi teksti: "$
read -t 10 VASTUS$
$
debug "VASTUS: $VASTUS"$
Sõnastiku kasutamine
Bash v. 4 võimaldab kasutada sõnastikku (ingl. k. associative array). Nt olgu failisüsteemis sellised failid
$ pwd /home/priit/skriptid $ find . -type f ./sql/konvert_ee/konvert_20120515.sql ./sql/konvert_ee/konvert_20120515a.sql ./sql/konvert_ee/konvert_20120515b.sql ./sql/konvert_20120520a.sql ./sql/konvert_20120505.sql ./sql/konvert_20120520b.sql ./sql/konvert_20120520.sql
ning eesmärk käivitada, sõltumata sellest, millises kataloogis üks või teine skript asub, nad kronoloogilises järjekorras (kasutades seejuures faili nimes esinevat YYYYMMDD osa).
$ cat jarjesta-ja-kaivita.sh #!/bin/bash declare -A sql_kataloog for i in `cd /home/priit/skriptid; find sql -type f | xargs`; do j=`echo $i | sed 's/sql\/konvert_ee\///' | sed 's/sql\/konvert_lv\///' | sed 's/sql\///'` sql_kataloog[$j]=$i done for key in `export LANG=C; echo ${!sql_kataloog[@]} | tr " " "\n" | sort | tr "\n" " "` ; do echo psql ${sql_kataloog[$key]} done
kus
- declare -A sql_kataloog - kirjeldab sõnastik tüüpi muutuja
- find ja xargs abil moodustatakse kataloogiteedega failinimede nimekiri
- sql_kataloog[$j]=$i - omistatakse sõnastiku võtmele (nt konvert_20120515b.sql) vastav väärtus (nt sql/konvert_ee/konvert_20120515b.sql)
- export LANG=C abil saab mõjutada järjestust
- echo ... tr ... sort ... tr abil järjestatakse sõnastik võtmete järjekorras
Kävitamisel vajastatakse
$ ./jarjesta-ja-kaivita.sh psql sql/konvert_20120505.sql psql sql/konvert_ee/konvert_20120515a.sql psql sql/konvert_ee/konvert_20120515b.sql psql sql/konvert_ee/konvert_20120515.sql psql sql/konvert_20120520a.sql psql sql/konvert_20120520b.sql psql sql/konvert_20120520.sql
Tingimuse kasutamine programmi väljundkoodiga
If tingimusega saab kasutada lisaks test vms konstruktsioonidele ka programmide väljundkoode (ingl. k. exit code, exit status) arvestades asjaolu, et reeglina on väljundkood programmi töö ilma veata lõppemisel 0 ning igal muul juhul > 0. Nt sobiks sellise skripti abil kustutada mingi rakenduse töö käigus tekkivaid zip faile /tmp kataloogist
for i in $(find /tmp -maxdepth 1 -mtime +2 -type f | xargs); do if $(unzip -qt $i 1>/dev/null 2>&1) ; then rm $i fi done
Sõnedega töötamine
Sõnest (ingl. k. string) saab eralda osa selliselt, viienda positsiooni järelt lõpuni
$ sone="tuulevaikus" $ echo ${sone:5} vaikus
Või expr abil
$ sone="tuulevaikus" $ echo `expr substr $sone 6 7` vaikus
Kasulikud lisamaterjalid
Tühikuid sisaldavate failinimedega töötamine
Kui faili või katalooginimedes esinevad tühikud, siis selline konstruktsioon ei tööta
$ for i in *; do du -sk $i; done
aga töötab selline find + while kasutamine
$ find . -type d ! -name . | while read nimi; do du -sk "$nimi"; done 8 ./Teater Vanemuine 8 ./Kala maja 8 ./Supi linn
Skriptisiseste teadete ja veateadetega tegelemine
Bash shelli stdout ja stderr
0 Stdin - kasutatakse info programmi sisestamiseks 1 stdout - kasutatakse info kirjutamiseks ekraanile 2 stderr - kasutatakse error teadete väljutamiseks
Näiteks veateadete faili logimine toimib nii
$ program-name 2> error.log
Nii veatedete kui niisama programmi sisteste teadete faili suunamiseks
$ command-name &>file
Selleks, et suunatada stderr ümber stdouti
$ command-name 2>&1
Programmi väljundi saab saata /dev/nulli lihtsa käsuga > /dev/null kahjuks ei tööta see programmidega, mis väljutavad ohtralt standard error 2 teateid. Selleks tuleb kasutada järgnevat süntaksit
$ command > /dev/null 2>&1
Suvaliste numbrite 0-10 genereerimine
Mitte seotud küll bashi sisemise struktuuri vaid hulga unixi/linuxi käskude koos kasutamisega aga tulem kulub sageli bashis ära.
grep -m1 -ao '[0-9]' /dev/urandom | sed s/0/10/ | head -n1
Mõned kasulikud skriptide näited
Mirrordamise skript Sobilik näiteks avaliku FTP serveri loomiseks.