next up previous contents
Nästa: 12.3 Ett spel Upp: 12. Avancerad Bashprogrammering Förra: 12.1 Fält

12.2 Funktioner

Man kan göra delprogram, funktioner, i sina Bash-program. Här är ett exempel, en ny version av hejvärlden:

#!/bin/bash

function dekorera()
{
  echo '****************************************'
  echo '****************************************'
  echo '** Program: hejvärlden                **'
  echo '** Copyright (c) 1997 Göran Andersson **'
  echo '****************************************'
  echo '****************************************'
}

dekorera
echo "Hej, världen!"

Först definieras funktionen dekorera. Varje gång funktionen anropas i programmet utförs de kommandon som står mellan klamrarna. Ett anrop av funktionen går till precis som ett anrop av till exempel programmet date: man skriver helt enkelt dess namn. Den första raden i själva programmet anropar funktionen. Den andra och sista programraden skriver sedan ut texten ''Hej, världen!''.$ hejvärlden
****************************************
****************************************
** Program: hejvärlden                **
** Copyright (c) 1997 Göran Andersson **
****************************************
****************************************
Hej, världen!
$

Funktioner kan ta argument precis som vanliga program. De är därför mycket mer användbara än alias. I programmet filinformation nedan finns en funktion som tar fyra argument. Dessa argument är tänkta att vara utskriften från wc, så det fjärde argumentet är namnet på en fil medan de tre första är antalet rader, ord och tecken i filen.

#!/bin/bash
function information()
{
  echo "Filen $4 har $1 rader och är $3 byte lång."
}

for i ; do
  information $(wc "$i")
done

Programmet kör wc på varje fil vars namn finns bland dess argument. Utskriften från wc blir argument till funktionen information. I funktionen skrivs det ut hur många rader och tecken det finns i filen.$ filinformation bellman lenngren
Filen bellman har 12 rader och är 372 byte lång.
Filen lenngren har 19 rader och är 649 byte lång.
$

En funktion i ett skalprogram fungerar ungefär som vilket fristående kommando som helst. Skillnaden är att ingen ny process dras igång, funktionen tolkas av samma Bashprocess som tolkar de övriga delarna av programmet. Därför kan man tex använda samma variabler i funktionen som i de övriga delarna av programmet; om en variabel får ett nytt värde i funktionen så påverkas dess värde i huvudprogrammet, och om den nuvarande katalogen ändras med kommandot cd i funktionen, så påverkar denna ändring hela programmet.

Följande program gör samma sak som programmet räkna i avsnitt 11.2. Den har en funktion, skriv_svar, som tar en textsträng som argument. Funktionen skriver ut textsträngen som ett meddelande, och läser sedan in variabeln SVAR.

#!/bin/bash

function las_in_svar()
{
  read -p "$1" SVAR
}

TAL1=$(( $RANDOM%10+1 ))
TAL2=$(( $RANDOM%10+1 ))
las_in_svar "Vad är $TAL1+$TAL2? "
until (( SVAR == TAL1+TAL2 ))
do
  echo 'Fel fel fel!'
  las_in_svar "Ange $TAL1+$TAL2 igen: "
done
echo 'Rätt svar!'

Så här kan vi lära programmet skrivtal alla tal upp till en miljon:

#!/bin/bash

ENTAL=([1]=ett två tre fyra fem sex sju åtta nio tio elva \
       tolv tretton fjorton femton sexton sjutton arton nitton)
TIOTAL=([2]=tjugo trettio fyrtio femtio sextio sjuttio åttio nittio)

function tilltusen()
{
  (( $1>99 )) && echo -n ${ENTAL[$1/100]}hundra && set $(( $1%100 ))
(( $1>19 )) && echo -n ${TIOTAL[$1/10]} && set $(( $1%10 ))
echo -n ${ENTAL[$1]}
}

if (( $1>999 )) ; then
  tilltusen $(( $1/1000 ))
  echo -n tusen
fi
tilltusen $(( $1%1000 ))
echo

Den gamla versionen av skrivtal utgör nu funktionen tilltusen. Om talet har fler än tre siffror, så körs tilltusen med talet delat med 1000 som argument, och ordet ''tusen'' skrivs ut. Därefter körs tilltusen med talets tre sista siffror som argument.$ skrivtal 254388
tvåhundrafemtiofyratusentrehundraåttioåtta
$ skrivtal 7000
sjutusen
$

En funktion som anropar sig själv sägs vara rekursiv. Programmet träd nedan har en rekursiv funktion, kataloger. Programmet ritar ett diagram över underkatalogerna till en given katalog. Om ett argument ges till träd så används detta som startkatalog, annars startar träd i den nuvarande katalogen.

#!/bin/bash

function kataloger()
{
  local FIL KAT M N INDRAG
  declare -i N=0 M=1
  echo -n "$1"
  INDRAG="$2${1//?/ }"
  cd "$1"
  for FIL in * ; do 
    [ -d "$FIL" ] && KAT[N+=1]="$FIL"
  done
  if (( N==0 )) ; then
    echo
  elif (( N==1 )) ; then 
    echo -n '---' 
    kataloger "${KAT[1]}" "$INDRAG   "
  elif (( N>1 )) ; then
    echo -n '-+-'
    kataloger "${KAT[1]}" "$INDRAG | "
    while (( (M+=1)<N )) ; do
      echo -n "$INDRAG |-"
      kataloger "${KAT[M]}" "$INDRAG | "
    done
    echo -n "$INDRAG"' `-'
    kataloger "${KAT[N]}" "$INDRAG   "
  fi
  cd ..
}

kataloger "${1:-.}" ''

Funktionen ska anropas med två argument; det första anger startkatalogen och det andra är en textsträng som ska skrivas ut före varje katalognamn. Funktionen använder ett antal lokala variabler. En lokal variabel är unik för varje enskild körning av funktionen. Lokala variabler får alltså vara ifred inom funktionen, de kan inte ändras någon annanstans. Låt oss prova programmet!$ träd /usr/local
/usr/local-+-bin
           |-include
           |-lib-+-netscape
           |     |-site_perl---i386-linux
           |     |-texmf---doc
           |     `-xemacs---site-lisp
           |-man
           |-sbin
           `-share---emacs-+-19.34---site-lisp
                           |-20.2---site-lisp
                           `-site-lisp


next up previous contents
Nästa: 12.3 Ett spel Upp: 12. Avancerad Bashprogrammering Förra: 12.1 Fält
Goran Andersson
1999-03-08