Difference between revisions of "Bash scripts"

From Teknologisk videncenter
Jump to: navigation, search
m (while)
m (Afvikling af shell scriptet)
 
(18 intermediate revisions by 2 users not shown)
Line 4: Line 4:
 
Det er vigtigt at scriptet ligger i et bibliotek der er med i søgning i variablen [[Bash variable#PATH|$PATH]]
 
Det er vigtigt at scriptet ligger i et bibliotek der er med i søgning i variablen [[Bash variable#PATH|$PATH]]
 
<source lang=cli>
 
<source lang=cli>
[heth@mars ~]$ <input>who am i</input>
+
[heth@mars ~]$ who am i
<notice>heth</notice>            ttyp2    Aug 24 07:51 (192.168.22.136)
+
heth           ttyp2    Aug 24 07:51 (192.168.22.136)
  
[heth@mars ~]$ <input>echo $PATH</input>
+
[heth@mars ~]$ echo $PATH
/sbin:/bin:/usr/sbin:/usr/bin:<notice>/home/heth/bin</notice>
+
/sbin:/bin:/usr/sbin:/usr/bin/home/heth/bin
 
</source>
 
</source>
 
Biblioteket hvor brugeren ''heth'' skal ligge sin scripts hedder ''/home/heth/bin''. Opret dette bibliotek hvis det ikke eksisterer og skift til dette bibliotek.
 
Biblioteket hvor brugeren ''heth'' skal ligge sin scripts hedder ''/home/heth/bin''. Opret dette bibliotek hvis det ikke eksisterer og skift til dette bibliotek.
 
<source lang=cli>
 
<source lang=cli>
[heth@mars ~]$ <input>mkdir /home/heth/bin</input>
+
[heth@mars ~]$ mkdir /home/heth/bin
[heth@mars ~]$ <input>cd /home/heth/bin</input>
+
[heth@mars ~]$ cd /home/heth/bin
 
</source>  
 
</source>  
 
== Oprettelse af scriptet ==
 
== Oprettelse af scriptet ==
 
Før vi opretter scriptet er det nødvendigt at vide hvor [[bash]] er installeret på maskinen. Bash programmet skal alle andre programmer er normalt placeret i et ''bin'' eller ''sbin'' bibliotek. På min maskine er den installeret i ''/usr/bin/bash'' som vist nedenfor.
 
Før vi opretter scriptet er det nødvendigt at vide hvor [[bash]] er installeret på maskinen. Bash programmet skal alle andre programmer er normalt placeret i et ''bin'' eller ''sbin'' bibliotek. På min maskine er den installeret i ''/usr/bin/bash'' som vist nedenfor.
 
<source lang=cli>
 
<source lang=cli>
[heth@mars ~/bin]$ <input>whereis bash</input>
+
[heth@mars ~/bin]$ whereis bash
bash: <notice>/usr/bin/bash</notice> /usr/local/man/man1/bash.1.gz /usr/ports/shells/bash
+
bash: /usr/bin/bash /usr/local/man/man1/bash.1.gz /usr/ports/shells/bash
 
</source>
 
</source>
 
Opret scriptet med din ynglingseditor. [[pico editor|pico]],[[nano editor|nano]],[[edit editor|edit]],[[emacs editor|emacs]] eller [[vi editor|vi]]. vi editoren findes på alle versioner af Linux og Unix, og er derfor en god editor at kende. Den kan dog drille lidt, så vælg [[pico editor|pico]] hvis du er i tvivl - og den er installeret på din Linux/Unix boks.
 
Opret scriptet med din ynglingseditor. [[pico editor|pico]],[[nano editor|nano]],[[edit editor|edit]],[[emacs editor|emacs]] eller [[vi editor|vi]]. vi editoren findes på alle versioner af Linux og Unix, og er derfor en god editor at kende. Den kan dog drille lidt, så vælg [[pico editor|pico]] hvis du er i tvivl - og den er installeret på din Linux/Unix boks.
Line 25: Line 25:
 
filen oprettes med
 
filen oprettes med
 
<source lang=cli>
 
<source lang=cli>
[heth@mars ~/bin]$ <input>vi script1</input>
+
[heth@mars ~/bin]$ vi script1
 
</source>
 
</source>
 
Indtast nedenstående bash script
 
Indtast nedenstående bash script
Line 39: Line 39:
 
For at afvikle shell scriptet skal bash vide at det er en udførbar fil. Altså et program der kan blive til en process.  
 
For at afvikle shell scriptet skal bash vide at det er en udførbar fil. Altså et program der kan blive til en process.  
 
<source lang=cli>
 
<source lang=cli>
[heth@mars ~/bin]$ <input>ls -l script1</input>
+
[heth@mars ~/bin]$ ls -l script1
<notice>-rw-r--r--</notice> 1 heth  heth  99 Aug 24 10:41 script1
+
<notice>-rw-r--r--  1 heth  heth  99 Aug 24 10:41 script1
[heth@mars ~/bin]$ <input>chmod +x script1</input>
+
[heth@mars ~/bin]$ chmod +x script1
[heth@mars ~/bin]$ <input>ls -l script1</input>
+
[heth@mars ~/bin]$ ls -l script1
<notice>-rwxr-xr-x</notice>  1 heth  heth  99 Aug 24 10:41 script1
+
-rwxr-xr-x 1 heth  heth  99 Aug 24 10:41 script1
 
</source>
 
</source>
  
 
nu er scriptet klar til at køre
 
nu er scriptet klar til at køre
 
<source lang=cli>
 
<source lang=cli>
[heth@mars ~/bin]$ <input>script1</input>
+
[heth@mars ~/bin]$ script1
Hvad er dit navn: <input>Mickey Mouse</input>
+
Hvad er dit navn: Mickey Mouse
 
Dit navn er Mickey Mouse
 
Dit navn er Mickey Mouse
 
</source>
 
</source>
 +
 
= Loops =
 
= Loops =
 
Der er flere foskellige måder at lave loops på i scripts. Hvilken metode der skal anvendes i hvilket tilfælde er baseret på erfaring.  
 
Der er flere foskellige måder at lave loops på i scripts. Hvilken metode der skal anvendes i hvilket tilfælde er baseret på erfaring.  
Line 58: Line 59:
 
I eksemplet herunder kan det ses at kommandoen ''ls -l script1'' går godt fordi filen ''script1'' eksisterer. Variablen '''$?''' indeholder ''exit'' status fra den sidste process der afsluttede. Denne indeholder her '''0''' som betyder det gik godt.  
 
I eksemplet herunder kan det ses at kommandoen ''ls -l script1'' går godt fordi filen ''script1'' eksisterer. Variablen '''$?''' indeholder ''exit'' status fra den sidste process der afsluttede. Denne indeholder her '''0''' som betyder det gik godt.  
 
<source lang=cli>
 
<source lang=cli>
[heth@mars ~/bin]$ <input>ls -l script1</input>
+
[heth@mars ~/bin]$ s -l script1
 
-rwxr-xr-x  1 heth  heth  88 Aug 24 11:43 script1
 
-rwxr-xr-x  1 heth  heth  88 Aug 24 11:43 script1
[heth@mars ~/bin]$ <input>echo $?</input>
+
[heth@mars ~/bin]$ echo $?
<notice>0</notice>
+
0
 
</source>
 
</source>
  
 
I eksemplet herunder kan det ses at kommandoen ''ls -l script190'' fejler fordi filen ''script190'' ikke eksisterer. Variablen '''$?''' indeholder ''exit'' status fra den sidste process der afsluttede. Denne indeholder her '''1''' som betyder at kommandoen fejlede .
 
I eksemplet herunder kan det ses at kommandoen ''ls -l script190'' fejler fordi filen ''script190'' ikke eksisterer. Variablen '''$?''' indeholder ''exit'' status fra den sidste process der afsluttede. Denne indeholder her '''1''' som betyder at kommandoen fejlede .
 
<source lang=cli>
 
<source lang=cli>
[heth@mars ~/bin]$ <input>ls -l script190</input>
+
[heth@mars ~/bin]$ ls -l script190
 
ls: script190: No such file or directory
 
ls: script190: No such file or directory
[heth@mars ~/bin]$ <input>echo $?</input>
+
[heth@mars ~/bin]$ echo $?
<notice>1</notice>
+
1
 
</source>
 
</source>
 
== while ==
 
== while ==
Line 97: Line 98:
 
done
 
done
 
</source>
 
</source>
 +
 
== for ==
 
== for ==
'''SYNTAX:'''
+
'''SYNTAX:'''
for NAME [in WORDS ... ;] do COMMANDS; done
 
 
 
 
::'''for NAME in WORDS'''
 
::'''for NAME in WORDS'''
 
::'''do'''
 
::'''do'''
Line 124: Line 124:
 
</source>
 
</source>
  
 +
= beslutninger =
 +
Man har ofte brug for at tage ja/nej beslutninger i scripts. For eksempel om en fil eksisterer.
 +
== if ==
 +
'''SYNTAX:'''
 +
::'''if''' ''COMMAND''
 +
:: '''then'''
 +
::: COMMANDS
 +
:: '''[ else'''
 +
::: ''COMMANDS'' ''']'''
 +
:: '''fi'''
 +
----
 +
'''FORKLARING:'''
 +
::Hvis ''exit'' status fra COMMAND i if linien er '''0''' udføres kommandoerne efter '''then'''.
 +
::Hvis ''exit'' status fra COMMAND i if linien er '''1''' udføres kommandoerne efter '''else''', hvis '''else''' sætningen eksisterer. Den er sat i firkantede paranteser [] hvilket betyder at den er optionel - man kan selv vælge om den skal med.
 +
::En '''if'' sætning skal mindst indeholde et '''then''' og et '''fi''' (if stavet bagfra)
 +
----
 +
'''EKSEMPEL:'''
 +
::Bash scriptet herunder finder ud af om ''Anders And'' har startet programmet. Der anvendes programmet [[test]]
 +
<source lang=cli>
 +
#!/usr/bin/bash
 +
echo -en "Hvad er dit navn: "
 +
read NAVN
 +
 +
if test "$NAVN" == "Anders And"
 +
then
 +
  echo "Hej Anders"
 +
else
 +
  echo "Hej $NAVN har du set Anders And"
 +
fi
 +
</source>
 +
== case ==
 +
case WORD in [PATTERN [| PATTERN]...) COMMANDS ;;]... esac
 +
'''SYNTAX:'''
 +
::'''case''' ''WORD'' '''in'''
 +
:: ''PATTERN'' '''['''''PATTERN''''']'''... COMMANDS
 +
:::::::: ''';;'''
 +
::...
 +
:: '''esac'''
 +
----
 +
'''FORKLARING:'''
 +
::Indholdet af variablen ''WORD'' bliver sammenholdt med de ''patterns'' som står i '''case''' listen. Hvis indholdet af ''WORD'' passer med ''pattern'' udføres komanderne indtil ''';;'''. Hvis der ikke findes et passende '''pattern''' til indholdet af ''WORD'' kan ''pattern'''et '''*''' anvendes som default.
 +
::VÆR OPMÆRKSOM på at første ''match'' anvendes. Så hvis ''pattern'' '''*)''' er det første i listen vil den altid passe, og resten aldrig blive checket. 
 +
----
 +
'''EKSEMPEL:'''
 +
::Bash scriptet herunder finder ud af hvem brugeren er.
 +
<source lang=cli>
 +
#!/usr/bin/bash
 +
 +
echo -en "Tast dit navn: "
 +
read NAVN
 +
 +
case $NAVN in
 +
  Per|per) echo "Velkommen Per"
 +
          date
 +
          ;;
 +
  Ulla|ulla|Ib|ib)
 +
          echo "Hej Ulla eller Ib"
 +
          ;;
 +
  Brit?|brit?) echo "Hej Britt eller er det Brita?"
 +
          ;;
 +
  *ur*)    echo "Dit navn indeholder ur, så du er sikkert Kurt eller Sigurd."
 +
          ;;
 +
  *)      echo "Dig kender vi ikke?"
 +
          ;;
 +
esac
 +
 +
</source>
 +
= Udskrivning til skærm =
 +
Til udskrivning på skærmen er der to grundliggende indbyggede funktion i '''bash''' som anvendes. Fælles for begge funktioner er kontroltegnene. 
 +
== echo ==
 +
== printf ==
 +
= Beregninger i scripts =
 +
Til beregninger i scripts kan der anvendes mange programmer eller indbyggede funktioner. Til simple beregninger kan [[let (bash)|let]] eller [[expr]] anbringes. Se Afsnit nedenfor. Til komplicerede beregninger kan [[bc]] eller [[dc]] blandt andet anvendes. (bc anbdefales)
 +
== Sammenligning af let og expr ==
 +
Følgende eksempel viser hvor meget performance der kan vindes ved at anvende den indbyggede funktion [[let (bash)|let]] i [[bash]] i stedet for at anvende det separate program [[expr]]. Grunden til at det tager så lang tid at anvende [[expr]] er at [[bash]] skal starte en ny process hvergang [[expr]] udføres. (100.000 gange ialt)
 +
<source lang=cli>
 +
[heth@mars ~]$ <input>cat test-let-expr</input>
 +
#!/usr/bin/bash
 +
 +
echo "#################### using let ####################"
 +
A=0
 +
TIMESTART=$(date +%s)
 +
while test $A -lt 100000
 +
do
 +
let A=A+1
 +
done
 +
let TIME=`date +%s`-TIMESTART
 +
echo "It took $TIME seconds for let to count to $A"
 +
 +
echo "#################### using expr ###################"
 +
A=0
 +
TIMESTART=$(date +%s)
 +
while test $A -lt 100000
 +
do
 +
A=`expr $A + 1`
 +
done
 +
let TIME=`date +%s`-TIMESTART
 +
echo "It took $TIME seconds for expr to count to $A"
 +
[heth@mars ~]$ <input>./test-let-expr</input>
 +
#################### using let ####################
 +
It took <notice>4</notice> seconds for let to count to 100000
 +
#################### using expr ###################
 +
It took <notice>250</notice> seconds for expr to count to 100000
 +
</source>
 +
'''''BEMÆRK:''''' I eksemplet ovenfor at ''VARIABEL=$(kommando)'' er det samme som ''VARIABEL=`kommando`''<br/>
 +
I ovenstående eksempel kunne [[let (bash)|let]] faktisk køre endnu hurtigere ved at anvende autoincrement operatornen ++. Udskift linien ''let A=A+1'' med ''let A++''.
  
 
+
= Ofte anvendte utilities =
 +
== cut ==
 +
== grep ==
 +
== tr ==
 +
== stty ==
  
{{#css:
+
{{Source cli}}
   
 
    pre {  font-family: Lucida Console; font-weight: bold; font-size: 14px; color: #00FF00; background: black; margin: 10px 50px; width: 800px; line-height: 200%; overflow: auto;}
 
}}
 
 
[[category:bash]][[category:linux]][[category:UNIX]]
 
[[category:bash]][[category:linux]][[category:UNIX]]

Latest revision as of 06:45, 4 April 2024

Denne artikel er en del af den samlede dokumentation af bash.

Mit første bash script

Hvor skal script-filen placeres

Det er vigtigt at scriptet ligger i et bibliotek der er med i søgning i variablen $PATH

[heth@mars ~]$ who am i
heth            ttyp2    Aug 24 07:51 (192.168.22.136)

[heth@mars ~]$ echo $PATH
/sbin:/bin:/usr/sbin:/usr/bin/home/heth/bin

Biblioteket hvor brugeren heth skal ligge sin scripts hedder /home/heth/bin. Opret dette bibliotek hvis det ikke eksisterer og skift til dette bibliotek.

[heth@mars ~]$ mkdir /home/heth/bin
[heth@mars ~]$ cd /home/heth/bin

Oprettelse af scriptet

Før vi opretter scriptet er det nødvendigt at vide hvor bash er installeret på maskinen. Bash programmet skal alle andre programmer er normalt placeret i et bin eller sbin bibliotek. På min maskine er den installeret i /usr/bin/bash som vist nedenfor.

[heth@mars ~/bin]$ whereis bash
bash: /usr/bin/bash /usr/local/man/man1/bash.1.gz /usr/ports/shells/bash

Opret scriptet med din ynglingseditor. pico,nano,edit,emacs eller vi. vi editoren findes på alle versioner af Linux og Unix, og er derfor en god editor at kende. Den kan dog drille lidt, så vælg pico hvis du er i tvivl - og den er installeret på din Linux/Unix boks.

filen oprettes med

[heth@mars ~/bin]$ vi script1

Indtast nedenstående bash script

#!/usr/bin/bash

echo -en "Hvad er dit navn: "
read NAVN
echo -e "Dit navn er $NAVN"

Afvikling af shell scriptet

For at afvikle shell scriptet skal bash vide at det er en udførbar fil. Altså et program der kan blive til en process.

[heth@mars ~/bin]$ ls -l script1
<notice>-rw-r--r--  1 heth  heth  99 Aug 24 10:41 script1
[heth@mars ~/bin]$ chmod +x script1
[heth@mars ~/bin]$ ls -l script1
-rwxr-xr-x 1 heth  heth  99 Aug 24 10:41 script1

nu er scriptet klar til at køre

[heth@mars ~/bin]$ script1
Hvad er dit navn: Mickey Mouse
Dit navn er Mickey Mouse

Loops

Der er flere foskellige måder at lave loops på i scripts. Hvilken metode der skal anvendes i hvilket tilfælde er baseret på erfaring. For at forstå loops er det vigtigt at forstå en process exit status. En process returnerer en værdi til bash der beskriver hvordan process forløb.

I eksemplet herunder kan det ses at kommandoen ls -l script1 går godt fordi filen script1 eksisterer. Variablen $? indeholder exit status fra den sidste process der afsluttede. Denne indeholder her 0 som betyder det gik godt.

[heth@mars ~/bin]$ s -l script1
-rwxr-xr-x  1 heth  heth  88 Aug 24 11:43 script1
[heth@mars ~/bin]$ echo $?
0

I eksemplet herunder kan det ses at kommandoen ls -l script190 fejler fordi filen script190 ikke eksisterer. Variablen $? indeholder exit status fra den sidste process der afsluttede. Denne indeholder her 1 som betyder at kommandoen fejlede .

[heth@mars ~/bin]$ ls -l script190
ls: script190: No such file or directory
[heth@mars ~/bin]$ echo $?
1

while

SYNTAX:

while COMMAND
do
COMMANDS
done

FORKLARING:

while udfører kommandoerne der står mellem do og done hvis kommandoen efter while går godt - altså har en exit status på 0. Herefter springer den tilbage og udfører while forfra. Hvis kommandoen efter while altid har en exit status på 0 vil while sætningen køre i en uendelig løkke. (Kan stoppes med <CTRL>-C
Hvis exit status er forskellig fra 0 udføres kommandoerne mellem do og done ikke og while kommandoen afsluttes helt.

EKSEMPEL:

I eksemplet herunder anvendes kommandoen test for at teste om variablen COUNT er mindre end eller lig med '-le (Lesser than or Equal to).
Bash scriptet herunder skriver 100 linier på skærmen hvor COUNT tælles op fra 1 til 100.
#!/usr/bin/bash

COUNT=1

while test $COUNT -le 100
do
  echo "Count har talt til $COUNT"
  let COUNT=COUNT+1
done

for

SYNTAX:

for NAME in WORDS
do
COMMANDS
done

FORKLARING:

for udfører kommandoerne der står mellem do og done for hvert enkelt ord i listen WORDS. Variablen NAME vil efter tur indeholde hvert ord der står i listen WORDS
Hvis exit status er forskellig fra 0 udføres kommandoerne mellem do og done ikke og while kommandoen afsluttes helt.

EKSEMPEL:

Bash scriptet herunder skriver 5 linier på skærmen. En for Hans, en for Ulla ....
#!/usr/bin/bash

VENNER="Hans Ulla Grethe Svend Bo"

for VEN in $VENNER
do
  echo "Jeg har en ven der hedder $VEN."
done

beslutninger

Man har ofte brug for at tage ja/nej beslutninger i scripts. For eksempel om en fil eksisterer.

if

SYNTAX:

if COMMAND
then
COMMANDS
[ else
COMMANDS ]
fi

FORKLARING:

Hvis exit status fra COMMAND i if linien er 0 udføres kommandoerne efter then.
Hvis exit status fra COMMAND i if linien er 1 udføres kommandoerne efter else, hvis else sætningen eksisterer. Den er sat i firkantede paranteser [] hvilket betyder at den er optionel - man kan selv vælge om den skal med.
En if sætning skal mindst indeholde et then' og et fi (if stavet bagfra)

EKSEMPEL:

Bash scriptet herunder finder ud af om Anders And har startet programmet. Der anvendes programmet test
#!/usr/bin/bash
echo -en "Hvad er dit navn: "
read NAVN

if test "$NAVN" == "Anders And"
then 
  echo "Hej Anders"
else
  echo "Hej $NAVN har du set Anders And"
fi

case

case WORD in [PATTERN [| PATTERN]...) COMMANDS ;;]... esac

SYNTAX:

case WORD in
PATTERN [PATTERN]... COMMANDS
;;
...
esac

FORKLARING:

Indholdet af variablen WORD bliver sammenholdt med de patterns som står i case' listen. Hvis indholdet af WORD passer med pattern udføres komanderne indtil ;;. Hvis der ikke findes et passende pattern til indholdet af WORD kan patternet * anvendes som default.
VÆR OPMÆRKSOM på at første match anvendes. Så hvis pattern *) er det første i listen vil den altid passe, og resten aldrig blive checket.

EKSEMPEL:

Bash scriptet herunder finder ud af hvem brugeren er.
#!/usr/bin/bash

echo -en "Tast dit navn: "
read NAVN

case $NAVN in
  Per|per) echo "Velkommen Per"
           date
           ;;
  Ulla|ulla|Ib|ib)
           echo "Hej Ulla eller Ib"
           ;;
  Brit?|brit?) echo "Hej Britt eller er det Brita?"
           ;;
  *ur*)    echo "Dit navn indeholder ur, så du er sikkert Kurt eller Sigurd."
           ;;
  *)       echo "Dig kender vi ikke?"
           ;;
esac

Udskrivning til skærm

Til udskrivning på skærmen er der to grundliggende indbyggede funktion i bash som anvendes. Fælles for begge funktioner er kontroltegnene.

echo

printf

Beregninger i scripts

Til beregninger i scripts kan der anvendes mange programmer eller indbyggede funktioner. Til simple beregninger kan let eller expr anbringes. Se Afsnit nedenfor. Til komplicerede beregninger kan bc eller dc blandt andet anvendes. (bc anbdefales)

Sammenligning af let og expr

Følgende eksempel viser hvor meget performance der kan vindes ved at anvende den indbyggede funktion let i bash i stedet for at anvende det separate program expr. Grunden til at det tager så lang tid at anvende expr er at bash skal starte en ny process hvergang expr udføres. (100.000 gange ialt)

[heth@mars ~]$ <input>cat test-let-expr</input>
#!/usr/bin/bash

echo "#################### using let ####################"
A=0
TIMESTART=$(date +%s) 
while test $A -lt 100000
do
 let A=A+1
done
let TIME=`date +%s`-TIMESTART
echo "It took $TIME seconds for let to count to $A"

echo "#################### using expr ###################"
A=0
TIMESTART=$(date +%s)
while test $A -lt 100000
do
 A=`expr $A + 1`
done
let TIME=`date +%s`-TIMESTART
echo "It took $TIME seconds for expr to count to $A"
[heth@mars ~]$ <input>./test-let-expr</input>
#################### using let ####################
It took <notice>4</notice> seconds for let to count to 100000
#################### using expr ###################
It took <notice>250</notice> seconds for expr to count to 100000

BEMÆRK: I eksemplet ovenfor at VARIABEL=$(kommando) er det samme som VARIABEL=`kommando`
I ovenstående eksempel kunne let faktisk køre endnu hurtigere ved at anvende autoincrement operatornen ++. Udskift linien let A=A+1 med let A++.

Ofte anvendte utilities

cut

grep

tr

stty