Er der fejl eller mangler på siden? Så skriv gerne til hacker(snabel-a)matfystutor.dk
BASH Scripting
Bash (Bourne-Again SHell) scripting er en god ting at kunne, for det er rigtig brugbart. Det er lidt det samme som batch-scripting på Windows®, altså det at lave .bat filer, men bare med en anden syntax. Det kan i sidste ende spare dig en hel del tid når du arbejder med større projekter, og/eller bare skal køre de samme kommandoer mange gange fx kopiere .class filer til Tomcat mappe, og genstarte tomcat.
At starte simpelt
Ethvert script skal starte med en linie, der oplyser hvilket program scriptet skal køres med, i det her tilfælde /bin/bash:
#!/bin/bash
De efterfølgende linier indeholder så kommandoer, fx:
#!/bin/bash echo "Hello World!"
Det ovenstående skriver "Hello World!" ud til konsollen.
Man kan også definere variabler. Det nedenstående svarer til det ovenstående:
#!/bin/bash hej="Hello World!" echo $hej
Man kan også tage output fra en anden kommando og bruge som variabel:
#!/bin/bash hej="Hello $(whoami)!" echo $hej
Det ovenstående tager output fra whoami, som er dit brugernavn, og skriver Hello foran. Outputtet bliver: Hello brugernavn!
Men det er jo ikke mit navn, tænker du så, og nej det har du ret i. Man kan derfor tage imod input fra brugeren med read kommandoen:
#!/bin/bash echo Indtast dit navn: read hej echo "Hello $hej!"
Nogle gange vil man tilføje ekstra bogstaver til en variabel fx:
#!/bin/bash banan="banan"; echo "$banan i flertal er ${banan}er".
Man skal i dette tilfælde omringe variabelnavnet med ${}. Dette skyldes at bash ellers ville lede efter en variabel der hed $bananer og give en runtime-fejl, da denne ikke fandtes.
Boolean værdier og tests
I linux afslutter alle programmer med en return code. Bash ser return code 0 som sand, og alt andet som falskt.
$ echo "Hello World!" | grep Hello Hello World! $ echo $? 0
echo $? ser hvad den sidste return code var, og udskriver den. I dette tilfælde returnerede grep 0, hvilket betyder at strengen "Hello" fandtes i "Hello World!"
test kommandoen bruges til at evaluere simple boolean udtryk, fx:
$ test 10 -lt 5 #Tester om 10 er mindre end (less than) 5 $ echo $? 1 #Det er det ikke, da return code er forskellig fra 0 $ test -n "Hello World!" #Tester om strengen "Hello World!" har en non-zero længde (længde der ikke er nul) $ echo $? 0 #Det har den, da return code er 0
test har et usædvanligt alias, nemlig [. Denne notation skal dog afsluttes med en ]
$ [ 10 -lt 5 ] $ echo $? 1
Husk på, at der skal være mellemrum mellem de forskellige argumenter, for ellers fejler det:
$ [ 5 -lt 4] #Ingen mellemrum mellem 4 og ] bash: [: missing ']'
Argumenter for test kommandoen, og forklaringer:
Fil tests | Forklaring |
---|---|
-d fil | Er fil en mappe |
-f fil | Er fil en almindelig fil |
-L fil | Er fil et symbolsk link |
-r fil | Eksisterer fil og er den læsbar |
-w fil | Eksisterer fil og er den skrivbar |
-x fil | Eksisterer fil og er den eksekverbar |
-s fil | Eksisterer fil og er dens størrelse forskellig fra 0 |
fil1 -nt fil2 | Er fil1 nyere end fil2 |
fil1 -pt fil2 | Er fil1 ældre end fil2 |
Streng tests | Forklaring |
---|---|
s1 = s2 | Streng s1 er lig med s2 |
s1 != s2 | Streng s1 er forskellig fra s2 |
-z s1 | Streng s1 har længde 0 |
-n s1 | Streng s1 har længde forskellig fra 0 |
Numeriske tests | Forklaring |
---|---|
a -eq b | Heltal a er lig med b |
a -ne b | Heltal a er forskellig b |
a -gt b | Heltal a større end b |
a -ge b | Heltal a større eller lig med b |
a -lt b | Heltal a mindre end b |
a -le b | Heltal a mindre eller lig med b |
Kombinering af tests | Forklaring |
---|---|
t1 -a t2 | AND: Både t1 OG t2 er sande |
t1 -o t2 | OR: Enten t1 ELLER t2 er sand |
! din_test | Udeluk en test, her bliver din_test falsk |
\( din_test \) | Paranteser bruges, som i matematik, til at gruppere udtryk |
bash har indbyggede kommandoer true og false, som returnerer hhv. 0 og 1:
$ true $ echo $? 0 $ false $ echo $? 1
Disse vil være brugbare når der skal laves if-else sætninger.
If sætningen
If sætningen vælger imellem en vilkårlig mængde alternativer, hvor hver af dem også kan indeholde en eller flere if sætninger. Den simpleste if-sætning er en if-then:
#!/bin/bash if [ $(whoami) = "root" ] #Hvis return code er 0 then echo "Du er superbrugeren" #Udfør dette kode fi
Så er der den lidt mere komplekse if-then-else:
#!/bin/bash if [ $(whoami) = "root" ] then echo "Du er superbrugeren" else echo "Du er en aldmindelig gut" fi
Bemærk at if afsluttes med fi, som er det omvendte af if.
Til sidst har vi if-then-elif-else sætningen, hvor der selvfølgelig kan forekomme vilkårligt mange elif imellem:
#!/bin/bash if [ $(whoami) = "root" ] then echo "Du er superbrugeren" elif [ "$USER" = root ] echo "Du er måske superbrugeren" elif [ "$bestikkelse" -gt 10000 ] echo "Du kan betale dig til superbruger status" else echo "Du er bare en almindelig gut" fi
case sætningen
Case er lidt ligesom if, men den tester kun forskellige tilstande af én boolean, hvor if kan teste flere forskellige.
Case kan være ret handy:
#!/bin/bash echo 'Hvad vil du gerne lave?' read svar case "$svar" in spise) echo "OK, tag en hamburger" ;; sove) echo "OK, godnat så" ;; *) echo "Jeg er ikke sikker på hvad du vil lave" echo "Vi ses nok i morgen" esac
Bemærk at case afsluttes med esac, som if gjorde med fi. Den generelle form ser sådan her ud:
case $streng in udtryk1) body1 ;; udtryk2) body2 ;; .... udtrykN) bodyN ;; *) body_else ;; esac
Hvor $streng er en variabel af en art, og udtryk1...udtrykN er udtryk strengen testes på. Hvert udtryk har et tilhørende body, dvs. kode der bliver udført, og denne skal afsluttes med ;; som vist foroven. Den sidste del *) er ligesom en else for en if-sætning, det er det, der bliver udført, hvis $streng ikke passer i nogle af udtrykkene. Et andet eksempel følger:
case $bogstav in X) echo "Bogstavet er et X" ;; [aeiouøæå]) echo "Bogstavet er en vokal" ;; [0-9]) echo "Bogstavet er et ciffer" ;; *) echo "Jeg ved ikke hvad bogstavet er" esac
Løkker
While-løkken gentager et sæt af kommandoer så længe et udtryk er sandt.
while udtryk #Så længe udtrykket er sandt (kommandoen returnerer 0) do body done
Bemærk at løkker altid afsluttes med done
Betragt eksemplet herunder. Scriptet hedder mit_script:
#!/bin/bash i=0 while [ $i -lt 3 ] do echo "$i" let "i += 1"; #Man kan også bruge i=$(($i+1)) done
For at køre scriptet skal man sørge for det er eksekverbart,
$ chmod +x mit_script #Sørger for det er eksekverbart $ ./mit_script #Kører scriptet 0 1 2
Der er også until løkken, som fortsætter med at gøre noget, indtil et udtryk bliver sandt:
#!/bin/bash i=0 until [ $i -ge 3 ] do echo "$i" let "i += 1"; done
Kørslen af while og until eksemplet ser ens ud, da det er to måder at gøre det samme på.
Til sidst er der for-løkken, den itererer over en liste:
for variabel in liste do body done
Betragt eksemplet:
#!/bin/bash for name in Jørgen Jens Jonas do echo "$name er min ven" done
Ved kørsel ser det sådan ud:
$./mit_script Jørgen er min ven Jens er min ven Jonas er min ven
For løkken er især brugbar når man skal iterere over filer:
#!/bin/bash for file in *.doc do echo "$file er en træls Microsoft Word fil" done
Den ovenstående løkker finder alle .doc filer, og udskriver filnavn er en træls Microsoft Word fil.
Som et supplement til løkkerne er der break og continue.
Break kommandoen springer ud af den nuværende løkke:
#!/bin/bash for name in Jørgen Jens Jonas do echo "$name er min ven" if [ "$name" = "Jens" ] then break fi echo "og" done echo "Færdig"
Kørslen ser således ud:
$ ./mit_script Jørgen er min ven og Jens er min ven #Her sker break-et, og echo "og" bliver ikke udført Færdig
Continue kommandoen derimod springer videre til næste iteration:
#!/bin/bash for name in Jørgen Jens Jonas do echo "$name er min ven" if [ "$name" = "Jens" ] then continue fi echo "og" done echo "Færdig"
Kørslen ser således ud:
$ ./mit_script Jørgen er min ven og Jens er min ven #Her sker break-et, og echo "og" bliver ikke udført, da løkken springer videre Jonas er min ven #Her er den sprunget over echo "og" og fortsat løkken og Færdig
At køre scripts
Som nævnt før, skal scriptet være eksekverbart før man kan køre det. Dette gøres med chmod +x sriptsti/scriptnavn kommandoen.
Ud over det skal bash scripts starte med #!/bin/bash før de kan eksekveres.
Man kan også køre scripts med bash:
bash scriptnavn
Kommandolinie argumenter
Bash scripts kan læse kommandolinie argumenter ligesom fx java. I bash scriptet refereres der til de forskellige argumenter med $1, $2, $3 ... $n variablerne.
$0 er en speciel variabel, der indeholder navnet på scriptet fx hvis mit_script så således ud:
#!/bin/bash echo "Scriptet hedder: $0"
Ville kørslen se sådan her ud:
$./mit_script Scriptet hedder: ./mit_script
Antallet af argumenter gemmes i en tredje variabel: $#
Argumenter gemmes også i en liste: #@ så man kan iterere over dem:
#!/bin/bash i=0 for arg in $@ do let "i += 1" echo "Argument $i : $arg"; done
En kørsel kunne se således ud:
$ ./mit_script arg1 arg2 arg3 Argument 1 : arg1 Argument 2 : arg2 Argument 3 : arg3
At afslutte med en Return Code
Man kan lade sine scripts afslutte med return codes, ligesom alle andre kommandoer i linux gør.
Dette gør man med udtrykket exit # hvor # skal erstattes med den return code man vil afslutte med:
#!/bin/bash if [ $# -lt 2 ] then echo "Fejl: Du skal skrive mindst to argumenter" exit 1 else echo "Mit navn er $1 og jeg kommer fra $2" fi exit 0
Og return code kan ses, som nævnt tidligere i denne artikel:
$ ./myscript Hacker Fejl: Du skal skrive mindst to argumenter $ echo $? 1 #Return code var 1 $ ./myscript Hacker CS Mit navn er Hacker og jeg kommer fra CS $ echo $? 0 #Return code var 0