Praktikum12 - Skriptimine Linuxis
Praktikum annab ülevaate käsurea skriptide loomisest Linuxis. Tihti on keerulisemate käsurea toimingute jaoks palju mugavam teha ette valmis skriptid, mida saab tulevikus perioodiliselt kasutada.
Sissejuhatus
Skript on sisuliselt tekstifail, kus sees on käsud. Skriptide koostamisel tuleb kasutada tekstiredaktorit, valikuid on Linuxis mitmeid. Vali see redaktor, mis sulle enim meeldib, kuid soovitame installeerida Kate
, kuna see teeb skriptide kirjutamise lihtsamaks.
sudo apt update
sudo apt install kate
- Otsi programmide loendist installeeritud programm
kate
ja käivita see. - Alternatiivsed terminalis töötavad editorid:
nano
,vim
. Alternatiivne GUI editor:gedit
.
Skriptide loomine ja käivitamine
Kui tahad skripti käivitada sarnaselt tavalise Linuxi programmiga, siis peab sellel olema korrektne päis (esimene faili rida) ning failile tuleb lisada käivitamisõigus. Skriptifaili päis määrab ära, millist käsureinterpretaatorit kasutatakse skripti käivitamisel.
- Pannes skripti päiseks ehk esimeseks reaks
#!/bin/sh
, määratakse skripti interpretaatoriks standardne POSIX-ühilduv käsuintepretaator (Bourne Shell).- Algselt kasutati Linuxis sh-na bash'i (Bourne-again shell), Ubuntus ning seega ka meie süsteemis on see alates versioonist 6.10 dash (Debian Almquist shell), mõnedes teistes süsteemides aga endiselt bash.
- Soovitav on kasutada skriptide jaoks tavalist Bourne Shelli /bin/sh, kui ekstra muid laiendusi tarvis pole – niisugused skriptid on kasutatavad ka muudes Unixi-põhistes operatsioonisüsteemides, kus puudub
/bin/bash
. Bash on sobiv interaktiivseks tööks terminalis ning mõnikord skriptide loomisel (juhul, kui Bashi laiendusi väga vaja on).
- Käsureaskriptide kokkuleppeline failide laiend on .sh, aga palju kasutatakse ka lihtsalt ilma laiendita failinimesid – oluline on, et fail oleks käivitatav.
- Silumisvahendina on kasulik lipp -x, sh käivitamisel, näiteks
sh -x skriptinimi.sh
või esimesel real#!/bin/sh -x
– see näitab ridahaaval välja, mida täidetakse.
Ülesanne 1
- Loo uus skriptifail esimene.sh, pane paika selle päis ning skripti sisuks lisa rida:
echo "Tere, tali!!"
- echo on käsuinterpretaatori käsk, mis väljastab ekraanile (standardväljundisse) oma argumendid
- Käivitamiseks on vajalik anda skriptile käivitamisõigus:
chmod 700 esimene.sh
- Käivita skript käsurealt nii:
./esimene.sh
Muutujad ja käsurea parameetrid
Skriptides on võimalik kasutada mitut erinevat tüüpi muutujaid:
- Protsessilt protsessile päranduvad keskkonnamuutujad:
$PATH
– kust otsida käivitatavaid programme, kui nende asukoht pole täisteega määratud$USER
– kasutajanimi$PWD
– protsessi hetkel aktiivne töökataloog
- Skripti sisendi muutujad, mille kaudu saab ligi skripti argumentidele ja muule skriptiga seotud informatsioonile:
$0
– skripti nimi$1 $2 .. $9
– skripti käsurea argumendid$$
– käesoleva interpretaatori (shell'i) PID
- Skriptisisesed lokaalsed kasutaja poolt määratud muutujad:
- Muutuja väärtustamisel piisab vaid nime määramisest:
nimi=Juku
(NB! Võrdusmärgi ees ja järel ei tohi olla tühikuid!)
- Muutuja väärtuse kasutamisel tuleb nime ette panna $-märk:
echo $nimi
- Kasutades ülakomasid (') teksti ümber, ei asendata seal sees muutujate väärtusi (ehk märk $ ei oma mõju, kui see on ülakomade vahel):
-
echo 'Ei asenda muutujat $1 tema väärtusega'
-
- Kui aga kasutada jutumärke ("), toimub asendus ilusti:
echo "Asendatakse muutuja $1 tema väärtusega"
- Muutuja väärtustamisel piisab vaid nime määramisest:
Ülesanne 2
- Skripti käivitamisel lisa argumendina oma nimi:
./esimene.sh "Juku Mets"
- Pane skript väljastama tervitust argumendis nimetatud isikule.
- Proovi, mis juhtub siis, kui argumendi määramisel jutumärke ei kasuta.
Interaktiivne sisend
Selleks, et küsida kasutaja käest täiendavat informatsiooni (näiteks failinime), saab kasutada read
-käsku nii:
echo "Sisesta väärtus:" read sisse echo "Sisestati: $sisse"
Ülesanne 3
- Muuda oma esimene.sh-skripti nii, et küsitakse kasutaja käest ükshaaval tema
nimi
,eriala
ningmatriklinumber
. - Sisestatud vastused tuleb väljastada ekraanile.
Juhtvood
Sarnaselt muude programmeerimiskeeltega on võimalik skriptides kasutada erinevaid tingimusi ja juhtvoogusid.
IF-ELSE
Teistest programmeerimiskeeltest juba hästi tuntud IF-ELSE konstruktsioon:
NB! Pööra tähelepanu nurksulgude ees ja järel tühikute kasutamisele!
#!/bin/sh a=$1 if [ $a -lt 1000 ] then echo "Sisestatud arv on vaiksem kui 1000" elif [ $a -ge 1000 -a $a -le 5000 ] then echo "Sisestatud arv on vahemikus 1000 kuni 5000" else echo "Sisestatud arv on suurem kui 5000" fi
- Operaatorid teksti (sõnede – kõik muutujad on siin sõnetüüpi) võrdlemisel:
- = – võrdne
- != – mittevõrdne
- -z – On tühi
- -n – Ei ole tühi
- Operaatorid arvude võrdlemisel (sõnede interpreteerimine tekstina esitatud arvudena):
- -eq – võrdne (ingl k. equal)
- -ne – mittevõrdne (ingl k. not equal)
- -lt – väiksem (ingl k. less than)
- -le – väiksem või võrdne (ingl k. less or equal)
- -gt – suurem (ingl k. greater than)
- -ge – suurem või võrdne (ingl k. greater or equal)
- Ning loogikaavaldised:
- -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.
While
While-tsükli sisu korratakse seni, kuni tingimus on tõene. Näites sooritatakse järgnev sisu, kuni muutuja $a on väiksem kümnest:
#!/bin/sh a=0 while [ $a -lt 10 ] do echo $a a=$(($a+1)) done
For
For-kordus on kasulik mingi nimekirja või listi läbi vaatamiseks:
#!/bin/sh a="Martin Janar Tiit Juku" for i in $a do echo "$i" done
NB! Kui tegemist on teksti sisaldavate muutujatega, siis on soovitav muutuja kasutamisel ümbritseda see jutumärkidega nii: echo "$i"
.
Ülesanne 4
- Esita skript, mis nimetab kõik etteantud kaustas asuvad laiendiga A (nt .txt) failid ümber laiendiks B (nt .csv), kus A ja B loetakse sisse argumentidena kasutajalt.
- Seda ja järgnevaid skripte soovitame käivitada
bash
is (faili alguses rida#!/bin/bash
), sestbash
i laiendused teevad tekstiasendusi lihtsamaks.- Vaata tsükli abil läbi aktiivses kataloogis leiduvad failid.
- Mingi käsu väljundi saab avaldisse asendada, ümbritsedes selle
$(...)
-konstruktsiooniga, näiteks käsuls
puhul:valjund=$(ls)
. - Sarnaselt saab käsu väljundit läbi vaadata ka for-tsükliga (
for i in $(ls)
).
- Mingi käsu väljundi saab avaldisse asendada, ümbritsedes selle
- Soovitatav on esialgu kirjutada kood, mis muudab kindla laiendi, näiteks
txt
i laiendikscsv
. - Kontrolli laiendit.
if [ ${i##*.} = txt ]; then
- Siin
${muutuja_nimi_ilma_dollarita##tekst}
asendab pikima võimaliku prefiksi (kõik enne "." oleva teksti)tühja stringiga
, seejärel kontrollime (=
), kas allesjäänud osa võrdub soovitud laiendiga (txt). Niisuguseid teisendusi on veel, vt man sh seest jaotist "Parameter Expansion".
- Siin
- Kui kontroll läheb läbi, nimeta fail ümber.
- Ümber saab faili nimetada käsu
mv
abil - Nime saab asendada näiteks käsu
sed
abil:
echo "failinimi.txt" | sed -e s/asendatav_text/asendus_text/
, ja selle programmi tulemus tuleks siis$(...)
-konstruktsiooni abilmv
-käsu argumendi sisse asendada. - Võime kasutada ka Parameter Expansion-funktsionaalsust.
${muudetav_text/mida_muudame/milleks_muudame}
- Ümber saab faili nimetada käsu
- Vaata tsükli abil läbi aktiivses kataloogis leiduvad failid.
$ fail=failinimi.txt; mv $fail $(echo $fail | sed -e s/.txt/.csv/g) $ fail=failinimi.txt;laiend1=.txt;laiend2=.csv; mv $fail ${fail/$laiend1/$laiend2}
- Esita skript, mis nimetab kõik etteantud kaustas asuvad laiendiga A (nt .txt) failid ümber laiendiks B (nt .csv), kus A ja B loetakse sisse argumentidena kasutajalt..
Ülesanne 5
- Loo skript, mis võtab argumendiks protsessi nime ning väljastab selle protsessi-ID (PID) ja nime.
- Otsi protsessi käsu
ps -A
väljundist. - Otsida võid kohe
ps -A
väljundis käsugrep
abil või siis iga rea puhul võrrelda, kas programmi nimi on õige. - Vaata kõik käsu väljundi read ükshaaval läbi. Seda on võimalik teha näiteks nii:
- Otsi protsessi käsu
#!/bin/bash IFS=$'\n' # Eraldaja muutmine tühikust reavahetuseks for line in $(ls) do echo "$line" done
- Selles näites muudetakse shelli muutuja
IFS
väärtus ajutiselt ümber reavahetuseks, et saaks käsu väljundit läbi vaadata ühe rea kaupa.
- Selles näites muudetakse shelli muutuja
- Vihjed: Väljasta protsessi nimi ja PID iga leitud protsessi kohta.
- Selleks, et leida esimest "sõna" tühikutega eraldatud "lauses" on võimalik kasutada
echo $line | cut -d ' ' -f1
, kus-fn
määrab ära, mitmes sõna, ning-d
määrab ära eraldaja. - Probleeme tekib siis, kui eraldajaks on rohkem kui üks tühik!
- Selle vältimiseks on võimalik lisada
echo
jacut
i vahele käsktr -s ' '
, mis eemaldab korduvad tühikud.
- Selle vältimiseks on võimalik lisada
- Probleeme tekitab (ajab tulbad nihkesse) ka esimene tühik, mis osadel ridadel on ja teistel pole.
- Selle probleemi saab kergesti lahendada, lisades kõigile ridade algusesse ühe tühiku lisaks ning siis kõik korduvad tühikud eemaldades (näiteks
echo " "$line | tr -s ' ' | cut -d ' ' -f2
, kus" "$line
lisab tühiku rea ette).
- Selle probleemi saab kergesti lahendada, lisades kõigile ridade algusesse ühe tühiku lisaks ning siis kõik korduvad tühikud eemaldades (näiteks
- Selleks, et leida esimest "sõna" tühikutega eraldatud "lauses" on võimalik kasutada
Funktsioonid
Tihtiesinevaid tegevusi skriptides on mõistlik kirjeldada funktsioonina, mida saab hiljem mitmeid kordi välja kutsuda.
- Funktsiooni saab sama skripti piires välja kutsuda nagu teist skripti või Linuxi käsku.
- Selleks, et funktsiooni (või ükskõik millise käsu) väljund avaldise sisse asendataks (näiteks muutuja väärtuse seadmisel), tuleb kasutada
`
-märke või $()-konstruktsiooni nii:echo "Funktsioonid väärtustatakse nii: $(minu_funktsioon 3 4 5)"
- Kasutage $(()), kui soovite, et teie kood arvutaks lisaks muutuja asendustele ka sulgude sees oleva tehte väärtuse (näites
a=$(($1 + $2))
, kusjuures siin$1
ja$2
on väljakutsumisel antud meetodi sisendparameetrid, mitte skripti käivitamisel sisestatud väärtused).
Näiteks loome funktsiooni, mis arvutab summat:
#!/bin/bash summa () { a=$(($1 + $2)) echo $a } a=$(summa 23 11) b=$(summa $a 1) echo $b
Ülesanne 6
- Loo funktsioon astendamiseks, kasutades korrutamistehet.
- Kasuta kas rekursiooni (9^5 == 9*(9^4))
- või näiteks WHILE/FOR-tsüklit.
- Väljasta oma skriptis 9^5 väärtus, kasutades loodud funktsiooni.
Skriptimine ja AI
Osad teist juba võibolla avastasid praeguseks, aga ChatGPT jms AI lahendused oskavad üldiselt pigem paremini, kui keskmine tudeng koodi kirjutada (k.a skriptida). Kui te praeguseks veel pole proovinud siis valige enda lemmik AI keskkond (ChatGPT, Google Gemini, Microsoft Bing jne) ja proovige seal lahendada käesoleva praktikumi ülesannet nr 6 (astendamine funktsiooni ja korrutamise abil).
Ülesanne 7: Esitage ekraanivaade, kus teie vabalt valitud AI keskkond lahendab edukalt ära, käesoleva praktikumi ülesande nr 6.
- NB! Pildil peab olema kogu veebilehitseja et pildilt hinnata:
- Millist keskkonda kasutasite?
- Milline oli teie küsimus AI-le? (ülesande püstitus AI-le)
- Milline oli AI vastus? (vajadusel esitage mitmel pildil).
Esmapilgul võib ju tunduda, et miks meil siis üldse on vaja õppida skriptimist, kui arvuti oskab ülesandeid hetkel juba paremini lahendada kui professionaal? Minu isiklik vastus ja põhjendus seisneb selles, et teil on endiselt vaja alusoskusi, et oskaksite verifitseerida (kontrollida) AI vastuseid ja lahendusi. Samas kasutan ise ja usun, et paljud aine kuulajad hakkavad edaspidi mitmeid IT tegevusi (näiteks skriptimine), sooritama AI abil. Seetõttu ka jätsime hetkel vastava praktikumiteema alles, aga proovisime siia lõppu teile ka näidata tulevikku ja efektiivset lähenemist sarnastele probleemidele tulevikus.
Boonusülesanne: Proovige koostada Linux skriptimise ülesannet, mis ei oleks teadlikult hägustatud või eksitava sõnastusega, millega AI hästi hakkama ei saa (koostab vale või vigase koodi ehk vastuse). Teisisõnu, õppejõud otsivad Linux skriptimise ülesannet, mida siia juhendisse panna olemasolevate asenduseks, mida tudengid peaksid siiski ise lahendama. Mida lühem skript seda suurem tõenäosus, et ma annan teile boonuspunkte. Saatke alop at ut dot ee
ülesande sõnastus, AI vastus, ja õige lahendus (töötav skriptikood) ning võite teenida kuni 1 boonuspunkti aine õppejõududelt.
Tulemuse esitamine
Oma GitHubi/GitLab esitusse lisa:
- Kõigi siniste ülesannete (3-6) lahendamiseks loodud skripti(de) sisu tekstina (hindaja peab saama skripti mugavalt kopeerida).
- Soovitav on panna kood GitHub/GitLab code block markdown märkide vahele. Näiteks:
```Siia tekst```
- Ei tohi olla ekraanivaatena lisatud.
- Soovitav on panna kood GitHub/GitLab code block markdown märkide vahele. Näiteks:
- Kõigi siniste ülesannete (3-6) lahendamiseks loodud skripti(de) käsurea väljundid.
- Peavad olema ekraanivaatena lisatud.
- Ülesanne 7: Esitage ekraanivaade, kus teie vabalt valitud AI keskkond lahendab edukalt ära, käesoleva praktikumi ülesande nr 6.
- Pildile esitatud nõudeid vaata ülesande kirjelduse juurest.
Kui teil on GitHub/GitLab valmis, siis lisage link esitusele moodle keskkonda, kust me teie lahenduse leiame. Moodle esitamise otselink: https://moodle.ut.ee/mod/assign/view.php?id=1221887
(Tähtaeg 2 nädalat)