Artikelkategori: Scripting
Skriven av nomicon 2003-09-25 13:09
url: http://www.slackwarelinux.se
Redigerad av: mdkdio  2020-04-15 21:29:30

Shellscripting

Hej och välkommen till en sida om scriptutveckling i sh/bash på linux. Det är en ny sida och det är första gången jag försöker med att lära ut något genom en websida, så du får ursäkta ifall saker ibland är oklart, eller så. Om du har några frågor kan du maila mig på kotten@linux.se så lovar jag att försöka svara så gott jag kan i frågan.

Min sida försöker vara tekniskt, praktiskt orienterad och de script jag har med som exempelscript är tagna, med få undantag, ur det verkliga livet. Ifall du har någon erfarenhet av programmering i något annat programmeringsspråk (php/perl/c eller något annat trevligt) kommer du säkerligen att känna igen mycket av koncepten och terminologin därifrån. Har du inte testat programmering tidigare gör det ingenting, i det här läget. Min sida är tänkt som en enkel introduktion till shellscripting, för folk som behöver veta lite om mycket. Jag håller emellertid på med en djupare text också, som jag hoppas skall kunna publiceras inom kort.

Att editera och köra script

Alla script jag skrivit i den här guiden går att sno rätt av. Ifall du skriver egna script och glömmer sh-bangen högst upp i scriptet (#!/bin/sh) så måste du köra dina script med kommandot sh. Glöm heller inte att sätta rätt rättigheter på dina script (chmod 755 scriptetsnamn). Jag förutsätter att du kan editera filer i din favoriteditor. Själv använder jag vi, för den finns alltid, men många använder idag d.ex. pico. Den får du med ifall du installera pine-paketet i linux. vi finns alltid med. Vilken du använder är upp till dig. Det viktigaste är att du har en editor, som du kan arbeta obehindrat med.


Några tips till hur du läser den här guiden:

1) När jag ger scriptexempel skriver jag dem med ett typsnitt i

kursiv

för att det skall vara enklare att läsa såhär (just det här scriptet gör inte så mycket, utan är bara med för att ge ett exempel).


#!/bin/sh
echo "Testscript"
# Det här är en kommentar.


2) När jag ger exempel på vad du som användare skriver på skärmen, skrivs den text du skriver med fet stil så att du enkelt skall skilja på vad som är "text på skärmen" och vad det är du skriver. Om det skulle vara att skriva kommandot ls, skulle det alltså se ut såhär:


#ls


Där jag använder tecknet # för att visa att detta görs som root (precis som bash visar det) och således tecknet $ för att visa att detta görs som någon annan, lokal användare på systemet.


Ett första script


Nu är det ändå dags för att skriva script, det är ju trots allt därför du surfat in på den här sidan? För att då börja någonstans, gör jag som de flesta andra och börjar med att skicka ut text på skärmen (något som kallas standard-out på programmerarspråk). Det görs lättast med kommandot echo. Jag kommer emellertid i det här exemplet att också använda en variabel.

En variabel är en bit data (text, siffror eller vad du vill) som vi enkelt sparar undan i minnet på datorn, för att sedan använda en, två eller flera gånger i vår kod. Nästan allt man gör i scripting är beroende av variabler, ifall man skall göra något annat än att bara skicka ut text på skärmen. Just i det här fallet använder vi dock den data vi lagrar i just en echo-sats, där vi alltså, helt enkelt, skickar ut den på skärmen. Mer om variabler kommer senare. Hajar du inte just nu vad en variabel är/gör så gör det inte så mycket.

Scriptet har emellertid en kommentar också. Det är raden som börjar med ett #. I shellscripting deklareras kommentarer alltid med ett #. En kommentar är text som inte visas på skärmen, men som programmeraren använder för att själv komma ihåg vad hans/hennes kod faktiskt gör. Jag skriver rätt mycket kommentarer i min kod, eftersom jag är dålig på att komma ihåg vad jag har gjort annars. Ett annat skäl att skriva kommentarer i sin kod är givetvis att andra också skall kunna se vad man gjort i efterhand, vilket ju underlättar ifall någon vill skriva om koden eller byta ut vissa delar.

På första raden i scriptet finns f.ö. en rad som beskriver att detta är ett script vi skriver i skalet (sh) som på ett linuxsystem ligger under katalogen bin. Detta är för att det skall gå så enkelt som möjligt att starta scriptet i efterhand, utan att användaren måste hålla koll på i vilket scriptspråk scriptet är skrivet. Bli vän med den raden, den kommer vara med i alla script jag skriver på den här sidan...


#!/bin/sh
HELLO="Hello world"
# Detta är en kommentar. Den kommer inte att visas.
echo $HELLO



Scriptet ovan gör egentligen inte så mycket mer än att det skriver ut texten "Hello world" på skärmen, när scriptet körs. Det viktiga här är hur du deklarerar och åberopar variabler. En variabel i shellscripting behöver egentligen aldrig deklareras annat än när den används (i vissa språk, som i C, måste man först berätta vad man vill att variabeln skall användas till och ge den ett namn och så, innan man kan använda den) och då skriver man bara vad den skall heta.

Att sedan åberopa innehållet i en variabel görs i det här fallet, när variabeln innehåller text (vad man på programmerarspråk kallar för en sträng) görs med ett $ före variabelnamnet. Se på scriptets sista rad.

Men vad är ett script?

Ett script är egentligen inget annat än en textfil, som innehåller de kommandon du vill köra. Här, där vi skriver script i skalet, måste vi således skriva kommandon som finns i skalet. Scriptet körs sedan, rad för rad, sekvensiellt, så att det börjar läsas högst upp och fortsätter nedåt.

Så ett script är alltså ett en samling kommandon, i det skal du skriver i. Vanliga linux-kommandon, alltså, staplade på varandra. När man förstår dessa huvudpunkter - att ett script är en textfil och att den innehåller vanliga linux-kommandon - är det inte svårt att själv utveckla script för vanligt förekommande systemadministrativa rutiner.


#!/bin/sh
# Ett enkelt script för att montera CD:n
# och visa innehållet...
mount /mnt/cdrom
# monterar cdromen till filsystemet...
# förutsätter givetvis att cdrom finns med i fstab.
cd /mnt/cdrom
ls -al
# Visar innehållet.
cd
# Ställer sig i användarens hemkatalog
umount /mnt/cdrom
eject
# Avmonterar och skickar ut CD-rom-skivan igen.



Exemplet ovan visar hur saker sker, helt sekvensiellt och innehåller bara, som synes, vanliga linux-kommandon för att montera och avmontera externa enheter till filsystemet, byta kataloger och visa innehåll.

Variabler och kontrollfunktioner - att välja mellan olika alternativ i scriptet

Vi har nu lärt oss ett par grundläggande saker om scripting: 1) det finns något som heter variabler är små bitar data vi kan spara undan för att använda i vårt script åter, och åter igen. 2) Script körs sekvensiellt och 3) script innehåller vanliga linux-kommandon. Alla dessa saker gör att vi, ifall vi lägger ihop dem nu kan skriva script som faktiskt GÖR något för oss.

Titta på scriptet ovan. Det som monterar en cd-skiva till filsystemet. Det gör allt i rätt ordning; Det monterar cd:n, ställer sig i det temporära filsystemets katalog, visar innehållet, ställer sig i en annan katalog innan det till sist avmonterar CD:n och skickar ut cdskivan ur inmatningsluckan på CD-romspelaren.

Tänk dig nu att vi skulle vilja ha två val till vårt script. Ett för att montera cd-skivan och ett för att avmontera cd-skivan. Vi måste då komma på ett sätt att skicka med argument till vårt script. Ett sådant argument skulle vi i så fall kunna spara i en variabel, men hur får vi scriptet att läsa vad som finns i variabeln och kontrollera vad det skall göra, därefter?

case-kommandot

Casekommandot är ett bra kommando att använda i sina script, för att förklara vad som händer i olika "fall" i scriptet. Ifall du gör såhär, kommer detta att hända. Ifall du gör på något annat sätt, kommer det här att hända.

Case-kommandot förutsätter en variabel det kan kontrollera. Normalt sett kan du använda variabeln $1, vilket betyder den första variabeln, som skapas automatiskt, ifall du skickar med ett argument till ditt script, när det körs. Ifall du således skriver:


$./mittscript start

kommer ordet start att skickas med som argument till scriptet och sparas i variabeln $1. När du nu vet att det går att skicka med argument till din kod kan man ju lätt skriva ett script som kontrollerar argumentet och beroende på vad det är monterar eller avmonterar cdromen. Jag kallar mitt script för cd med argumenten start/stop beroende på vad jag vill att det skall göra. Enligt följande:


echo "CD-hanterare - av Jesper Värn"
case $1 in
start)
# Kontrollerar ifall variabeln är start.
# I så fall händer följande:
echo "monterar CD skivan"
mount /mnt/cdrom
cd /mnt/cdrom
echo "här är innehållet:"
ls
echo "färdigt"
;;
# Avslutar det här caset...

stop)
# Kontrollerar ifall variabeln är stop.
# I så fall händer följande:
cd
umount /mnt/cdrom
eject
echo "färdigt"
;;
# Avslutar det här caset...

*)
# Kontrollerar ifall variabeln är något annat.
# I så fall händer följande:
echo "Skriv ./cd start eller ./cd stop"
exit 1
# Lämnar tillbaka till prompten
;;
esac
# case baklänges betyder att case är avslutat.


Scriptet kommer nu alltså att kontrollera vad du har skrivit för argument till det och då exekvera rätt kod. Skriver du inget argument alls till det kommer det att säga till hur du skall använda det. På ett enkelt sätt kan du nu avgöra "vilken väg" scriptkörandet skall ta genom ditt script, beroende på vilket argument som är skrivet. På precis samma sätt fungerar många script som är medskickade i linux, som kör igång vissa tjänster, som scripten i t.ex. init.d.

if - elif -else

Ett annat sätt att kontrollera vilken väg scriptets körning tar är med if - elif - else. Det fungerar egentligen på nästan samma sätt och vilken metod man använder är egentligen upp till en själv. Jag brukar personligen skriva script så att jag gör case för argument som är medskickade till scriptet, medan jag använder if-satser för att kontrollera vad som händer inom argumenten, ifall det behövs. Oj. Det blev en konstig utläggning. Låt oss först titta på vad kommandona är och hur de fungerar:

if är ett kommando som kan användas antingen för att kontrollera variabler, eller för att kontrollera andra kommandon i mitt shellscript. else är egentligen det motsatta. Ifall något inte är satt så gäller else, tänk det som i en mening. Saker är ANTINGEN något ELLER INTE. elif är den gyllene mellanvägen. Det är som ett "antingen är saker något eller så är de NÅGOT ANNAT, eller inte".

Låt mig visa med hjälp av ett exempel:


#!/bin/sh
if [ "$(whoami)" = "kotten" ]; then
# Här kollar vi ifall kommandot whoami ger kotten...
# i så fall händer...
echo "hej kotten"

elif ["$(whoami)" ="falken"]; then
# Annars, ifall whoami ger "falken"...
echo "greetings professor Falken"
echo "how about a nice game of chess?"

else
# Och i övriga fall är användaren ju inte känt...
echo "Howdy stranger"
fi
# fi är if baklänges och betyder att här slutar scriptet
# kontrollera variabler och fortsätter att köra på
# som vanligt...
echo "Klar!"



Loopar

När man i shellscripting vill att kod skall repetera sig själv, under kontrollerade former skriver man vad man på programmeringsspråk kallar för loopar. Vi skall i det här kapitlet titta lite närmare på 3 stycken loopar: for-loopen, until-loopen och while-loopen. De har olika funktion och används givetvis olika, beroende på vad du vill att din kod skall göra.

For-loopen

For-loopen används ifall man vill loopa igenom en lista, och för varje argument i listan göra något. Ifall ingen lista anges till loopen kommer den att ta den katalogstruktur den står i som input. Ett exempel:


#!/bin/sh
for A in *
# först sätts loopvillkoret upp. För varje fil
# i den här filstrukturen
do
echo $A
done
# skriv ut innehållet i variabeln A
# (filnamnet.) och sedan är loopen klar
# vilket visas med "done"
echo "klar"



Until-loopen

Until-loopen körs fram tills ett villkor har inträffat. Den lämpar sig således utmärkt till att till exempel övervaka andra funktioner i scriptet och fram tills dess att dessa inträffar, genomförs vad som står i loopen. Ett exempel:


#!/bin/sh
echo "kollar när användaren ture loggar in"
# Ett enkelt script för att kontrollera när
# ture loggar in. Skrivet av J. Värn 1995
until who | grep ture > /dev/null
# fram tills dess att who | grep ture ger något...
# skickas till /dev/null för att man skall slippa
# se varje misslyckat försök på skärmen...
do
sleep 3
# sov (vänta) i 3 sekunder.
# sedan kör vi kollen igen (se ovan)
done
# och nu har villkoret uppfyllts...
echo "ture har loggat in..."
echo "klart!"



En smart liten loop som man lätt kan bygga mycket avancerade script med, för att övervaka tjänster i ens maskin och beroende på vad som händer med dessa gör olika saker. Inte sällan använder jag just sådana här script vid säkerhetsövervakning av maskiner jag kontrollerar.

While-loopen

While-loopen fungerar precis som until-loopen, fast tvärt om, kan man säga. Loopen kommer att köra under tiden som ett villkor är sant. Den lämpar sig således också utmärkt för script med olika former av övervakningsfunktioner. Man vill ju se att saker antingen "händer" (med until-loopen) eller "inte händer" (med while-loopen). Låt mig visa med ett exempel för att övervaka att httpd inte dött:


#!/bin/bash
# Ett litet script för att övervaka httpd.
# Jesper Varn 1998
# ---------------------------------------

while ps -aux | grep httpd >/dev/null
do
sleep 3
done
echo "Nu har httpd dött. Starta om den."
echo "klart."
# klart



av Jesper "Kotten" Värn 2002 - 05 - 17 v0.01 GNU/GPL 2.0
 

×