Teejuht
Siin lehel on eeldatud, et inimesed midagi juba oskavad: ehk on hea vaadata neid lehekülgi, kui on probleeme:
I/O ümbersuunamine: <, >, >>, <<, |, 1>/dev/null, >&1
loogilised tehted: AND, NOT, OR, XOR
protsessid: ps, PID, PPID, exit code
Shell on see programm, mis käivitatakse peale süsteemi sisselogimist. Enamasti on selleks programm sh (bash), mis oskab reageerida linuxi käskudele. Võimalik on shelliks panna ka teisi programme. Nt. telnet, pine, passwd.
Shelli scriptid on käivitamiseõigusega tekstifailid, kus on sees tuntud shelli käsud soovitud järjekorras. Näiteks selline:
dw.sh:
#!/bin/sh
echo "Tere kangelane klaviatuuri taga"
date
w
ning andes kasu dw.sh
kuvatakse ekraanile midagi sellist:
Tere kangelane klaviatuuri taga
Laupäev, 6. Juuni 1998 12:12:28 EET DST
imre
polla
maali
vladik
NB! et and failile käivitamisõigus tuleb anda korraldus
chmod u+rwx dw.sh
õigusi saab näha käsuga ls -l
See on primitivne näide aga ideed kannab.
NB! pange tähele, et shell script algab #! ja interpretaatori
nimega /bin/sh.
Peab kohe ütlema, et shelli scriptide kirjutamiseks on vaja tunda linuxi käske ja nende võtmeid. Tihti on linuxi käsud juba iseenesest väga võimalusterohked ja õigetest võtmestest hulka kasu.
2. Minule tuttavad
käsud ja nende võtmed
NB! kasude kohta saab linuxis abi kui man
on installeeritud nii:
man kasunimi
man 5 kasunimi
(vahest on asja abileht jagatud sektsioonideks - 1, 2, 3 ....)
nt. man bash
Enamus siintoodutest tegelevad andmete stdout-i (standard output) saatmise ja soteerimisega. Esialgu on neid mõtet anda kasurealt ja vaadata mida nad teevad.
korraga võib käsureale anda rohkem kui ühe käsu kusjuures nad tuleb siis semikooloniga eraldada
who; date; uptime
Käsud ja võtmed
echo -n "Tere inimene" | ei pane reavahetust jargi |
echo -e "\n\tNagu C-s\n" | tolgendab \-asju nagu C |
nl < failinimi, voi nl failinimi | nummerdab read |
nl -n ln failinimi | left justified (default) |
nl -n rn failinimi | rigth justified |
nl -n rz failinimi | right justified, leading zeros |
cat -n failinimi | nummerdab read |
cat -A failinimi | naitab koiki symbolied |
cut -b 2-3 failinimi | trykib iga rea 2 ja 3 -nda symboli |
cut -f2 failinimi | valjasta ainult teine tulp, eeldusel, et TAB on tulpade vahel |
cut -d" " -f3 failinimi | kuva 3. tulp ja eraldajaks on tühik |
w -h | naita kasutajaid ilma p6iseta |
sort filename voi sort -r failinimi | sorteeri nagu votmetega antud |
wc -l voi wc -w voi wc -c | kuvab vastavalt lines, word voi characters |
du -S -a | kuvab kataloogis olevate failide suurused |
df | disk free |
free | naitab malukasutust |
top | programm mis naitab palju - q lopetab |
ps aux | grep imre | mina näen nii enda protsesse |
Toodutega saab päris palju ära teha, nt.
1. kuvame kataloogi sisu faili suuruste järjekorras
ls -la | sort +4n
2. ja failinimede tähestikulises järjekorras
ls -la | sort +8
3. kasutame samade tulemuste saamiseks käsku du:
(raalige välja mis nende vahel erinevat on!)
du -S -a | sort
du -S -a | sort -n
du -S -a | sort +0
du -S -a | sort +0n
du -S -a | sort +1
du -S -a | sort +1n
3. Ülakomad - kolme sorti - 'apostrophe', "apostrophe", `grave`
Ülekomade vahele satub tavalist kolme sorti asju:
a) tavalisi stringe (string - sõna või lihtsalt järgnevus sümboleid)
Minu nimi on Imre
b) käske
who
c) keskkonnamuutujaid
$HOSTNAME
Erinevad ülakomad interpreteerivad neid erinevalt
- järgnevad selgitavad näited:
1. 'midagi vahel' - märke nimetatakse inglise keeles apostrophe
echo 'who; date $HOSTNAME'
ei interpreteeri mitte midagi, lihtsalt kirjutab mis on nii nagu on.
2. "midagi vahel" - double quote
echo "who; date $HOSTNAME"
ei interpreteeri käske vaid kirjutab sümbolid ekraanile; küll aga asendab keskkonnamutujad vastavate väärtustega
3. `midagi vahel` - grave
echo `who; date`
interpreteerib kõiki käskudena kusjuures ei pane reavahetusi; et paneks tuleb näiteks nii teha
echo "`who; date`"
See pole veel kogu armastus aga suur kunst olla
nende erinevate ülakomade sättimine.
4. Muutujate kasutaine shell scriptis.
Scriptides saab kasutada ka muutujaid ning script saab oma tegevuse
ajal küsida inputi ka mõnest failist või klaviatuurilt.
No sciptis saab teha kõike mida käsurealt ja vist rohkemgi
veel. Olgu üteldud, et mitmed nö. programmid pole tegelikult
mitte binarid vaid hoopis shelli scripid. Nt. adduser uute kasutajate lisamiseks.
Shell scriptis saab kasutada konstruktsioone sarnaselt programmeerimiskeeltele:
for, while, if, for ..
Ja muutujate nimed scriptides algavad nagu keskkonnamuutujate nimed
dollariga, nt. $muutuja. Scriptides saab kasutada olemasolevaid keskkonnamuutujaid.
Järgnevad mõned näited.
1. käsurea kolm argumendid -script kirjutab millised olid ja ütleb parameetrite arvu ning parameetrite väärtused:
#!/bin/sh
echo $3 $2 $1 $#
2. for tsükli näide, for tsükkel teeb iga nn. list toodud asjaga ühe ringi
#!/bin/sh
for i in mina sina tema meie teine nemad
do
echo $i
done
for tsükkel teeb oma ringi iga käesolevas kataloogis oleva objektiga
#!/bin/sh
for i in *
do
echo $i
done
5. Aritmeetilised
tehted ja klaviatuurilt input. NB! expr juures on vaja tyhikuid
panna!
#!/bin/sh
summa=0;
echo sisestage kaks arvu
echo -n "a: "
read a
echo -n "b: "
read b
echo a + b = `expr $a + $b`;
echo a - b = `expr $a - $b`;
echo a / b = `expr $a / $b`;
echo "korrutustehe tuleb kuidagi kavalalt teha";
teine võimalus aritmeetlilisteks teheteks:
#!/bin/sh
summa=0;
echo sisestage kaks arvu
echo -n "a: "
read a
echo -n "b: "
read b
echo "a +b = $(($a + $b))";
echo "a-b = $(($a - $b))";
echo "a / b = $(($a / $b))";
echo "a * b = $(($a * $b))";
ja kolmas
#!/bin/sh
summa=0;
echo sisestage kaks arvu
echo -n "a: "
read a
echo -n "b: "
read b
echo "a + b = $[$a + $b]";
echo "a - b = $[$a - $b]";
echo "a / b = $[$a / $b]";
echo "a * b = $[$a * $b]";
Ja jagamine töötab vaid täisarvude korral :(
6. While konstruktsioon - loeb kuni while taga olev lause lõpetab tegevuse edukalt (nii öelda exit code 0)
See script lihsalt kuvab stdin-i suunatud teksti, toodud kujul peab viimane rida lõppema reavahetusega.
kaivitada: scriptname < tekstifail
#!/bin/sh
while read reakene
do
echo $reakene
done
Ja see nummerdab lisaks read:
#!/bin/sh
nr=0;
while read reakene
do
nr=`expr $nr + 1`
echo $nr $reakene
done
See on lobus programm mis kasutab programmi `tr "vahemik" "vahemik"` mis muudab koik standart inputi tulevad vaiketahed suurteks
#!/bin/sh
while read rida
do
echo $rida | tr "a-z" "A-Z"
done
while nagu programmeerimises, NB! tyhikud ja nende puudumine on olulised, eriti expr real.
#!/bin/sh
mi=0;
while [ $mi -lt 6 ]
do
echo "mi: $mi";
mi=`expr $mi + 1`;
done
7. if - konstruktsioon ning
test -imise tingimus (-gt, -lt, -e, -ne, -le, -ge : greater
than, less than, ..)
praktiliselt on ükskõik kas kasutada test $arv -gt 5 või
[ $arv -gt 5 ]
#!/bin/sh
echo Sisestage arv:
read arv
if test $arv -gt 5; then
echo oli viiest suurem
else
echo oli väiksem võrdne viiega
fi
sama, aga ilma test võtmesõnata:
#!/bin/sh
echo Sisestage arv:
read arv
if [ $arv -gt 5 ]; then
echo oli viiest suurem
else
echo oli väiksem võrdne viiega
fi
aga nii ütelda "way too cool" võimalus kasutada tingimusi on järgmine: mängitakse loogiliste AND ja OR peale.
tingimus1 AND tingimus2 mida kirjutatakse tingimus1 &&
tingimus2
tingimus1 OR tingimus2 mida kirjutatakse tingimus1 ||
tingimus2
AND tehe on tõene
vaid siis, kui mõlemad tigimused on tõesed.
AND on mittetõene kui kasvõi üks on mittetõene.
Vaatame kuidas arvuti tegeleb tehtega
kui (7 > 6 AND 6 < 7)
siis tee seda ja seda
vastasel juhul
toda ja toda
antud juhul tehakse seda ja seda. 7 on suurem 6 -st ja 6 väiksem
7 st.
tingimust loeb arvuti vasakult paremale:
Antud juhul veenub masin, et 7 on suurem 6 -st ja asub kontrollima
kuidas on lugu 6 < 7 tõesusega. Veenududes et mõlemad
on tõesed tuleb arvuti järeldusele, et AND on tõene.
Ja nii viiakse täide seda ja seda.
Praktiliselt on oluline see, et kui vasakul pool
olevad käsud lahenevad nö. positiivselt, siis täidetakse
ka paremal olevad käsud.
Vaatame aga teist olukorda:
kui (7 > 8 AND 6 < 7)
siis tee seda ja seda
vastasel juhul
toda ja toda
antud juhul viiakse täide korraldused toda ja toda kuvõrd
AND tehe annab ebatõese tulemuse. Ning vaatleme kuidas arvuti sellisele
järeldusele tuleb ning AND tehet teeb.
Esmalt teeb ta kontrolli kas 7 > 8, leiab et see on väär.
Kuivõrd AND tõesuseks on vajalik mõlema tingimuse
(vasakul ja paremal AND-st) tõesus siis arvuti ei hakkagi teist
poolt ( 6 < 7) kontrollima sest AND on nagunii mittetõene.
Praktiliselt on oluline see, et kui vasakul pool
olevad käsud lahenevad nö. negatiivselt, siis paremat poolt ei
asuta täitma.
konkreetne naide:
Teeme ls -i kataloogis kus on failid mina sina tema meie teie nemad
mina
sina
tema
meie
teie
nemad
ning nüüd: ls | grep tema
tema
aga nüüd: ls | grep tema 1>/dev/null && echo "olemas"
olemas
Selgitus: et vasakul pool && marke oleva konstruktsiooni viimane käsk andis positiivse tulemuse (st. leiti mida otsiti), siis on vasaku poole väärtus mingis mõttes tõene. Kuigi meid praktiliselt ei huvita loogilise tehte (tingimus1 && tingimus2) väärtus arvuti siiski leiab selle. Sellel AND tehte tegemise teel ta praktiliselt täidab paremal pool olevad käsud.
Sarnaselt OR tehe
ls | grep tema 1>/dev/null || echo "ei ole sellist"
mitte midagi
ls | grep tartu 1>/dev/null || echo "ei ole sellist"
ei ole sellist
Selgitus on sarnane eeltoodule. OR tehe on tõene kui
1. tingimus1 on tõene ja tingimus2 väär
2. tingimus1 on väär ja tingimus2 tõene
3. tingimus1 on tõene ja tingimus2 tõene
Niisiis, kui vasakul poole oleva tehete väärtus on tõene,
siis on OR tehte tulemus niikuinii tõene ja paremal pool olevat
asja ei kontrollita (käske ei täidata).
Praktiliselt on oluline see, et kui vasakul pool
olevad käsud lahenevad negatiivselt ainult siis täidetakse parema
poole käske.
Seda kas mingi käsk lahenes nii öelda
positiivselt või negatiivselt saab lihtsasti teada. Arvuti salvastad
viimase tulemuse keskkonnamuutujasse $?.
Proovige nt.
ls
echo $?
0
date
echo $?
0
ls leninvladimir $?
echo $?
1
(eelsusel, et sellist faili ei ole)
Siin ongi nüüd see jama, et õnnestumisel omandab $? väärtuse 0 ja muidu mingi teise arvu (nö. exit code). Tavaliselt on C -s õnnestumise väärtus 1. No traditsioonid, traditsioonid ...
Esitame veel ühe programmi paraleelselt kahel moel realiseerituna:
Programm küsib arvu ja ütleb on see viiest suurem või
mitte
#!/bin/sh
echo -n "Sisestage arv: "
read arv
if test $arv -gt 5; then
echo "oli viiest suurem"
fi
#!/bin/sh
echo "Sisestage arv: "
read arv
test $arv -gt 5 && echo "oli viiest suurem"
8. case konstruktsioon
üks praktiline näide case'st:
#!/bin/sh
echo "Programm töötab
lõpmatus tsüklis, väljumiseks C-c :)"
while :
do
echo -n "sisestage a: "
read a;
case $a in
[a-z]*) echo "väikese
tähega algav";;
[A-Z]*) echo "suure tähtega
algav";;
*) echo "midagi muud kui tähtega
algav";;
esac
done
näide kuidas teha valikuvõimalusi koos vaikimisivalituga:
suvi:~/ooo# k1.sh
Kuhu sõita soovite:
Tartu
Tallinn
Pärnu
Sisestage palun valik [Tartu]:
#!/bin/sh
vt=0;
echo "Kuhu sõita soovite:"
echo -e "\tTartu\n\tTallinn\n\tPärnu"
while [ $vt -ne 1 ]
do
vt=1;
echo -n "Sisestage palun valik
[Tartu]: ";
read valik
case $valik in
"") valik="Tartu"
;;
"Tartu") valik="Tartu"
;;
"Tallinn") valik="Tallinn"
;;
"Pärnu") valik="Pärnu"
;;
*) vt=0
;;
esac
if [ $vt -eq 1 ]; then
echo "Valsite $valik, tore";
else
echo "paha lugu, valige võimaluste seast ...";
fi
done
Muuseas, kui teha programm mis töötab võtmetega siis nende võtmete kontrolli olla case-ga hea teha.
9. Käsurealt "kohmakate" käskude andmine:
1. timer, nali - legaalne on anda korraldus:
bash# i=0; while [ $i -le 5 ]; do echo -n "$i"; date; sleep 1;
i=`expr $i + 1`; done
See on nagu script ise.
2. Script nummerdab kataloogis olevate failide nimed ja kuvab need tulbas
bash# a=0; for i in *; do a=`expr $a + 1`; echo $a $i ; done;
3. Script teeb sama mis eelminegi ainult failid esitatakse suuruse järjekorras
bash# a=0; for i in ` ls -l | sort +4n | awk '{print $9}'`; do a=`expr $a + 1`; echo $a $i ; done;
4. Mul oli selline probleem, et kasutati uut CD-Recorderit
ja ma polnud kindel ka minu kataloogitäis kraami ikka sai veatult
CD pinna peale. Ja halb oli see, te failinimede tähesuurust
oli muudetud (st. reastus mida ls näitab oli muutunud kui võrrelda
originaalkataloogi jaseda mis CD peal).
Tavaliselt kasutatakse data võrdlemiseks programmi diff -r kataloog1
kataloog2 aga mina seda teha ei saanud sest failide nimed ja järjekord
polnud ühesugune. Niisiis,
1. kasutasin alltoodud scripti ja nimetasin failide nimed ümber (tehes muidugi enne koopia :) lihtsalt 1, 2, 3 suuruse järjekorras (see eeldab, et kahte ühesuurust faili ei ole)
bash# a=0; for i in ` ls -l | sort +4n | awk '{print $9}'`; do a=`expr $a + 1`; mv $a $i ; done;
2. kasutasin diff-i vastavatele kataloogidele
10. Primary ja secondary prompt (tahistame PS1$ ja PS2>)
Minul isiklikult puudub selle võimaluse järgi karjuv
vajadus aga huvitav siiski:
kui anda selline korraldus prompti taha:
PS1$ while [ 1 ]; do date; sleep 1; clear; done
siis ilmub terminalilt yles aarde date mida iga sekund refresh'itakse
aga andes korralduse ridahaaval saab ka:
PS1$ while [ 1]
PS2> do date
PS2>sleep 1
PS2>clear
PS2>done
miks ta nii kaitub on ehk selle parast, et while [ 1 ] lõhnab
shelli jaoks väga lõpetamata lause järele ja ta on valmis
seda lõppu vastu võtma.
C - c lõpetab (Ctrl -c)
11. raktilised scriptid ehk pikad käskude kombinatsioonid
Siin on esitatud mõned (kõik kolm :) minu meelest mõnusat scripti mis on abiks olnud:
1. Kuvab tulpa kataloogis olevate nende
failide nimed milles string esineb:
fstr.sh:
#!/bin/sh
for a in `ls $1 | awk '{print $9}'`; do cat $a 2>/dev/null | grep $2
>/dev/null && echo "leidis: $a"; done
kaivitada:
fstr.sh kustkataloogistotsida midaotsida
2. Probleem: kataloogis on ainult
failid ja nende nimedes on igal vähemalt üks suur täht.
Script
asendab kataloogis olevate faililide nimed samade nimedega, ainult
kõik tähed on väikesed.
captolo.sh
#!/bin/sh
kataloog=$PWD;
cd $1;
for i in `ls`
do
echo $i;
mv $i `echo $i | tr "[A-Z]" "[a-z]";`
done;
cd $kataloog;
Kasutus:
captolo.sh katalooginimimillesonneedfailid
3. ftp - tegeija script. Kasulik kui on modemi
ühendus ja on soov mingist kolmandast masinast faile kopeerida teise
masinasse.
Kõigepealt logite neisse mõlemasse sisse, vatate kus
kataloogides midagi on, kas õigused on korras ja kas mahuvad ära.
Seejarel lahete teise masinasse mis tõmbama hakkab ja redigeerite
vastavalt scripti.
Ning siis jätate scripti tööle
ptf.sh:
#!/bin/sh
ftp -n -i ftp.funet.fi <<LOPP
quote user ftp
quote pass imre@
cd pub/Linux/mirrors/slackware/slakware/d1
lcd /home/imre/slackware/d1
bin
mget *
LOPP
NB! peale LOPP -u lõpus tuleb reavahetus panna. Siin on muidugi
see puudus, et ta ei konda kataloogistruktuure mistahes sügavusele
alla välja :)
Kasutus:
ptf.sh &
Ja veel üks ftp -tegeija - natuke instelligentsem. Failis kataloogid
on kirjas sama taseme kataloogid
(nt. slackware distribution):
kataloogid:
a1
a2
a3 ...
ja script on ise selline, f.sh:
#!/bin/sh
for i in `cat kataloogid`
do
ls
cd /home/imre/data
mkdir $i
cd $i
`ftp -n -i ftp.funet.fi <<LOPP
quote user ftp
quote pass imre@
cd "/pub/Linux/mirrors/slackware/slakware/$i"
bin
mget *
LOPP`
done
4. Script mis peaks kirjutama ekraanile kataloogis sisalduvate asjade suurused ja pikad nimed ilusti tulbas. Ta alati ei tööta õieti, millegipärast. Eks ise kontrollige. Ta on rekursiivne, st. ise ennast vajadusel uuesti käivitav.
liz.sh
#!/bin/sh
current="$PWD";
cd $1;
ls -Fdl $PWD/* 2>/dev/null;
for i in `ls -d $PWD/* 2>/dev/null`
do
if (! test -L "/$i") && (test -d "/$i"); then
liz $i;
fi
done;
cd $current;
Kasutus:
liz.sh katalooginimi
5. cksum -programmi kasutamine. See on küll praegu ühe erijuhu jaoks - kui kataloogison vaid failid ja mitte alamkatalooge aga ikkagi.
c1.sh:
#!/bin/sh
cd $1
for item in *
do
echo `cksum $item`
done
Kasutus:
c1.sh kataloog.kus.asuvad.failid
Sama asi ainult juhuks kui on Kataloog miles on vaid alamkataloogid ja neis omakorda vaid failid (nt. slackware distribution :)
c2.sh:
#!/bin/sh
cd $1
for i in *
do
cd $i
for k in *
do
echo `cksum $k` $i | awk '{print $1" "$2" ./"$4"/"$3}'
done
cd ..
done
Kasutus:
c2.sh kataloog.milles.on.alamkataloogis.ja.neis.failid
Ja nende scriptide output on mõistlik suunata faili ning siis pärast originaali ja enda oma võrrelda nt. diff, cmp, wc abil. Mitte käsitsi!