Boken Om Linux/Kapittel 16

16: Skallprogrammering rediger

Kommandofiler rediger

Skallet er en kommandotolker som tolker alle de kommandoene du skriver inn på systemledeteksten. Kommandoene blir utført interaktivt, dvs. kommando for kommando.

Det er også mulig å utføre programmer som består av flere kommandoer i rekkefølge. Dette får du til med en kommandofil som består av flere Linux-kommandoer. Du kan bruke teksteditorene vi eller emacs (kapittel 12) til å lage kommandofiler.

Et annet ord for kommandofil er batch-fil. En batch-fil kan i tillegg til de tradisjonelle Linux-kommandoene også inneholde kontrollstrukturer, variabler og argumenter. Det er ikke stor forskjell på å bruke tradisjonelle programmeringsspråk og å lage kommandofiler. Tilsvarende de forskjellige programmeringspråkene, har også skallene forskjellige kontrollstrukturer, variabler og argumenter.

De mest brukte skallene under Linux er:

  • Bourne Again-skall (bash)
  • T-skall (tcsh)
  • A-skall (ash)
  • B-skall (bsh)
  • Z-skall (zsh)

Men Linux støtter også skallene

  • Bourne-skall (sh)
  • C-skall (csh)
  • Korn-skall (ksh)

Disse 3 siste skallene følger med som standard under Unix V.4. Navnet på Bourne-skallet på de fleste UNIX-systemer er /bin/sh. Skallet har en BASIC-lignede syntaks. C-skallet bruker en annen syntaks, litt lik programmeringsspråket C, og på de fleste UNIX-system er navnet /bin/csh, Korn- og bash-skallet er utvidelser av Bourne-skallet og har mange av de avanserte egenskapene som du finner i zsh-skall. Korn og bash støtter et supersett av Bourne-skallets syntaks. Z-skallet er et supersett av ksh med mange forbedringer. Både A- og B-skallet er basert på sh-skallet med tilleggsegenskaper. For de som foretrekker å bruke C-skallsyntaks, er det nyttig å vite at Linux støtter tcsh, som er en utvidet versjon av det originale C-skallet.

Bourne- og C-skallene følger ikke med som standard i Linux, men disse skallene kan lastes ned gratis fra forskjellige steder på Internett (se kapittel 23).

Tcsh- og zsh-skallet bør brukes hvis du skal ha et interaktivt skall. Bruker du Tcsh- og zsh-skall, blir det meste av Bourne-skallsyntaksen godtatt. Men de fleste kontrollstrukturer, for eksempel if, for, while og case, har en egen syntaks under de to skallene.

Følgende momenter vil påvirke ditt valg av skall:

  • Skal skriptet være portabelt (for andre Unix-systemer)?
  • Hva skal gjøres? Programutvikling eller rene batch-jobber?
  • Hva er greiest for deg?
  • Smak og behag.

De fleste foretrekker Bourne-skallets syntaks med avanserte egenskaper fra bash eller ksh. Fordi begge støtter et supersett av Bourne-skallets syntaks, burde de fleste skall-skript skrevet i standard Bourne-skall virke med bash eller ksh.

Bourne-skallet er mest benyttet på Unix. Bourne-skallet anbefales hvis du skal utvikle kommandofiler (batch-filer) som skal flyttes til andre Unix-systemer. Systemadministrator (root) er i Linux satt opp med bash-skallet.

I dette kapitlet har jeg konsentrert meg om Bourne-skallets (sh) syntaks, da både bash og ksh er nedover-“kompatibelt" med dette. I stedet for å skrive bash-skall vil jeg videre i dette kapitlet bruke betegnelsen bash, som er navnet på skallet i Linux-verden. Alle kommandofilene i dette kapitlet vil virke både under Bourne-skall(sh) og bash-skall (bash).

Lage og kjøre kommandofiler rediger

Jeg har laget en kommandofil som heter test. Den inneholder flere skall-kommandoer som du kan utføre linje for linje fra kommandoledeteksten:

  1. !/bin/bash
  1. Kakespiseprogram

mat="kaker"

echo "Spiser du $mat"

echo 'Spiser du $mat'

Første linje betyr at dette er en bash-skallkommandofil. Du kan bruke # til å sette kommentarer i kommandofilen din. Vær oppmerksom på at når filen begynner med #, betraktes den som en kommandofil i csh- eller tcsh-skall.

I tredje linje tilordner jeg variabelen mat til tekststrengen kaker. Man kan når som helst i programmet tilordne en variabel. Skal du bruke variablene senere, spesifiseres du $ foran variabelen.

I fjerde og femte linje bruker jeg kommandoen echo. Den sender tekststrenger til skjermen. I fjerde linje bruker jeg anførselstegn på høyre og venstre side av en tekststreng. Dette gjør at innholdet av variabelen blir vist på skjermen. I femte linje bruker jeg ' (apostrof). Alt mellom apostrof blir dermed tolket som en "bokstavelig" tekststreng, og variabelinnholdet blir derfor ikke vist på skjermen. Dette viser jeg senere i sammenheng med jokere.

Skrive kommandofiler rediger

For å kunne skrive en kommandofil (program) må du kunne lage en tekstfil. Dette kan du gjøre ved å bruke cat-kommandoen.

Eksempel:

[david@nittedal david]$ cat > fil

Skal du lage større kommandofiler, er det best å bruke en editor. Du kan bruke vi eller emacs (kapittel 12), eller en eller annen editor som kan lagre filene i rent tekstformat uten koder (ASCII).

Kjøre kommandofiler rediger

Det finnes flere måter å kjøre en kommandofil på. Den enkleste er å la skallet gjøre det. Hvis du ønsker at sh- eller bash-skallet skal kjøre programmet test, skriver du:

[david@nittedal david]$ bash test

En annen metode er ved omdirigering av standard inndata:

[david@nittedal david]$ bash < test

Den vanligste måten å kjøre en kommandofil på er å gjøre den kjørbar. (Se kapittel 8.) Dette kan du gjøre ved å bruke kommandoen chmod:

[david@nittedal david]$ chmod u+x test

Deretter skriver du bare navnet på kommandofilen:

[david@nittedal david]$ test

Alle kommandofiler som har satt på x-bitet, kan kjøres direkte.

Enkle kommandofiler rediger

Jeg skal her vise eksempler på kommandofiler og hva de fører til. Den første kommandofilen, echosend, sender beskjed til andre brukere (terminalbilde/tty).

  1. !/bin/bash

echo "Hei du" > /dev/pts/0

Her sender jeg tekststrengen "Hei du" til den terminalbrukeren som bruker driveren /dev/pts/0. Filen echosend lager du med editoren vi.

Du starter kommandofilen med:

[david@nittedal david]$ echosend (Husk å sette x-bitet på filen)

Kommandofilen diskuse:

  1. !/bin/bash

echo "Diskforbruk"

du /home/elboth

Her får du blokkforbruket til /home/elboth.

Kommandofilen sendterm:

  1. !/bin/bash

sh | tee /dev/pts/1

Her sender jeg mitt terminalbilde til terminalen som bruker driveren /dev/pts/1. Mer om tee-kommandoen finner du ved å bruke man-kommandoen.

Kommandofilen sendut:

  1. !/bin/bash

cu -ltty1a -s9600 dir

Sender ut terminalpolling på serieporten. Mer om cu-kommandoen finner du ved å bruke man-kommandoen (sjekk at programpakken uucp er installert).

Kommandofilen listsort:

  1. !/bin/bash

ls /bin | sort

Sjekker filene i katalogen /bin og sorterer innholdet. (Du finner mer om sort-kommandoen i kapittel 13.)

Kommandofilen fcount:

  1. !/bin/bash

ls -l | sed 1d | wc -l

Teller opp antall filer. Ønsker du å vite mer om sed-kommandoen, kan du bruke man-kommandoen.

Variabler rediger

  * Variablene er lagerområder for data. Dataene i en variabel kan endres. Det er fire måter å definere skallvariabler på:
  * vanlig tildeling
  * posisjonsparametere
  * tildeling av posisjonsparametere
  * lesing med read-kommandoen 

Du bestemmer selv hva variablene skal inneholde. Navnet på en variabel kan ikke begynne på et tall og kan ikke ha noen spesialtegn. (Se kapittel 6 og 7.)

Vanlig tildeling av variabler rediger

Man kan tildele såkalte midlertidige variabler og miljøvariabler. Miljøvariabler er permanente, men verdiene kan endres.

Midlertidige variabler rediger

Midlertidige variabler blir skapt når du trenger dem. Ved hjelp av et likhetstegn kan du gjøre en tildeling.

Eksempler på midlertidige variabler:

datamaskin=DellPentumIII

nummer=3.14

mat=ost

pris=12

katalog=/home/david/c-filer

hjemmekatalog='pwd'

Ønsker du en nullverdi, skriver du:

prosent=

Du kan bruke variablene ved å legge til $ foran variabelen. Ønsker du å vite hva som er i variabelen, skriver du bare til skjermen med echo-kommandoen, for eksempel:

[david@nittedal david]$ echo $pris

[david@nittedal david]$ echo $hjemmekatalog

[david@nittedal david]$ cp prog.c $katalog

Her brukte jeg en variabel i en kopieringskommando.

Variabler som består av kontrollkarakterer, mellomrom eller skallkommandoer, må omringes med apostrofer, for eksempel:

[david@nittedal david]$ dato='date'

[david@nittedal david]$ bruker='who | wc -l'

Midlertidige variabler med apostrof rediger

Hvis en variabel inneholder en apostrof, må den omringes med anførselstegn, for eksempel:

[david@nittedal david]$ tekst="Mange PC'er er solgt"

Midlertidige variabler med anførselstegn rediger

Hvis en variabel inneholder anførselstegn eller tekst med mellomrom, må den omringes med anførselstegn.

[david@nittedal david]$ tekst=""Hei du""

Miljøvariabler (Systemvariabler) rediger

Miljøvariabler skrives alltid med store bokstaver og kjennetegnes ved at de har med ditt brukermiljø å gjøre. Eksempler på miljøvariabler i sh- og bash-skall er HOME, PATH og PS1.

Den spesielle skallvariabelen PATH kontrollerer hvilke programmer som kan utføres. PATH forteller noe om søkebanen for skalltolkeren. Uten PATH-kommandoen får du bare kjørt de programmene og kommandoene som er plassert i din lokale katalog.

Miljøvariabler kan brukes på samme måte som de midlertidige variablene. Prøv med $HOME.

[david@nittedal david]$ echo $HOME

Hjemmekatalogen vises nå på skjermen.

Viktige systemvariabler i sh- og bash-skall:

   PATH En liste over kataloger som kan bli søkt av kommandotolkeren; katalogene blir gjennomsøkt i den rekkefølgen som er satt opp i PATH. LOGNAME Brukernavnet (login-navnet) ditt. TERM Når du ser beskjeden terminaltype på skjermen, har Linux brukt TERM-variabelen til å definere terminaltype. Det finnes flere typer terminaler. De mest brukte er xterm, ansi, at386, vt52, vt100 og vt220. De fleste programmer må vite hva slags terminal du kjører. Sitter du på hovedkonsollet (PC-enheten) får du ingen beskjed om terminaltype. Kobler du deg derimot opp via RS232-porten, må du bestemme terminaltype. HOME Navnet på brukerens hjemmekatalog. MAIL Navnet på brukerens elektroniske postkasse, vanligvis plassert på /var/spool/mail. MAIL-variabelen brukes vanligvis til å endre søkebane og filnavn til postkassen. MAILCHECK Denne parameteren spesifiserer hvor ofte (i sekunder) posten skal sjekkes. PS1 I bash-skall definerer denne variabelen ledeteksten din. Standardverdi på ledeteksten for en bash-skall-bruker er $-tegnet og for en tcsh-skall bruker %-tegnet, men Red Hat redefinerer ledetekstene til begge skallene. PS2 Denne ledeteksten ser du når skallet ditt forventer mer inndata; den er en sekundær ledetekst. PS2-ledeteksten brukes også ved kommandolinjer som er lengre enn 80 tegn. Da vises PS1-ledeteksten på første linje, mens PS2-ledeteksten viser fortsettelsen av linjen. IFS Bestemmer hvilken variabel som skal være feltseparator.

Tildeling av posisjonsparametere rediger

Når en kommandofil kjøres, oppretter skallet posisjonsparametere. $0 viser navnet på kommandoen. $1 er det første argumentet, $2 er det andre, osv. opp til $9.

Starter du en kommandofil med et argument, blir navnet på kommandofilen posisjonsparameter $0, og argumentet blir $1. Har du forskjellig argument hver gang du starter en kommandofil, blir innholdet i $1 også forskjellig. Eksempel på kommandofil med fire argumenter:

[david@nittedal david]$ start a b c d

Her blir kommandofilen tilordnet $0, a tilordnet $1, b tilordnet $2, c tilordnet $3 og d tilordnet $4.

Du kan også direkte tilordne verdier på posisjonsparametere ved å bruke set-kommandoen, for eksempel:

[david@nittedal david]$ set IDGBooks Best på EDB

Her vil $1 bli tilordnet tekststrengen "IDGBooks", $2 tilordnet tekststrengen "Best", $3 tekststrengen "på" og $4 tekststrengen "EDB".

Prøver du med

[david@nittedal david]$ echo "$2 $3 $4 $1"

får du:

Best på EDB IDGBooks

Prøv med:

[david@nittedal david]$ set A B C

Parameterne får du ved å skrive:

[david@nittedal david]$ echo "$1 $2 $3"

A B C

Forhåndsdefinerte variabler rediger

Man har også forhåndsdefinerte variabler som kan brukes i kommandofiler til å konstruere forskjellige tester i kontrollstrukturer.

Forhåndsdefinerte variabler:

   $# gir antall argumenter som er gitt i en kommandolinje; har du kommandoen test A B C, så får $# verdien 3 $? gir status for den siste kommandoen som ble utført; er kommandoen feilfri, blir verdien null $n kommandoargumentet fra 1 til n $@ gir alle argumenter som er anbefalt, spesielt hvis quoting skal gjengis riktig: "$@" $* gir alle argumenter $$ gir prosessnummer på aktuell prosess $! gir prosessnummer på siste bakgrunnsprosess $- gir en liste over skallopsjoner som er brukt 

Forhåndsdefinerte variabler kommer i tillegg til posisjonsparametere.

Her kommer kommandofilen antall:

echo $#

Kommandofilen begynner med : for å indikere for skallet at det er et sh- eller bash-skall. Tegnet $# gir oss antall argumenter. Prøv å kjøre kommandofilen antall med argumentene a, b, c og d:

antall a b c d

4

Nå vil $0 være navnet på kommandoen (antall). $1 vil være a, $2 vil være b, osv. $1 til $9 varierer for hver gang antall kjøres.

Kommandofilen hvor:

who | grep $1

Eksempel på bruk av hvor-skriptet:

hvor else

else må da være en definert bruker.

Kommandofilen variabel:

  1. !/bin/bash

echo Antall argumenter er $#.

date &

echo Prosess-id fra dato-kommandoen var $!.

wait

echo Prosess-id av dette skallet er $$.

grep vt100 /etc/termcap

echo Returkoden fra grep var $?.

echo Jeg hadde følgende set med opsjoner $-.

Her har jeg en kommandofil hvor jeg bruker alle de forhåndsdefinerte variablene. Legg merke til at jeg ikke har brukt anførselstegn. Resultatet blir det samme om du skriver echo: Uttrykkene antall argumenter er $# og echo "Antall argumenter er $#" er likestilt.

Eksempel på bruk av kommandofilen variabel:

bash -x variabel A B > testfil

+ :

+ echo Antall argumenter er 2.

+ echo Prosess-id på dato‑kommandoen var 20719.

+ date

+ wait

+ echo Prosess id på dette skallet er 20718.

+ grep vt100 /etc/termcap

+ echo Returkoden fra grep var 0.

+ echo Jeg hadde følgende sett med opsjoner hx.

Mer informasjon om utføringsflagg (opsjoner) bash ‑x finner du senere i dette kapittelet (i avsnittet om skall-miljøet).

Variabler med read-kommandoen rediger

Ved hjelp av read‑kommandoen kan du lese en hel linje. Bruker du read i en programfil, leser skallet fra standard inndata og legger det i variabelen.

Eksempel:

  1. !/bin/bash

clear

echo "Hei!"

echo "Hva heter du? "

read svar

echo "Morsomt å hilse på $svar"

I dette eksemplet legger skallet input fra brukeren i variabelen svar og skriver teksten ut.

Utskriftstyring rediger

Ved omdirigering av standard utdata kan du bestemme hvor du vil legge resultatene fra en kommandofil. Standard utdata kan sendes til en terminal, en skriver eller en fil. Mer informasjon om omdirigering av standard inn- og utdata finner du i kapittel 9.

Bruker du echo-kommandoen, blir argumentet separert med et mellomrom og avsluttet med et linjeskift. Kommandoen echo forstår også spesielle koder, blant annet følgende:

-n forhindrer newline

-e tillater deg å bruke backslash/escape baserte tegn

   Følgende spesialtegn kan brukes: '\a' lyd '\b' backspace '\c' forhindrer ny linje '\f' formfeed '\n' newline '\r' carriage return '\t' horisontal tab '\v' vertikal tab '\\' backslash '\NNN' spesialkode 

NNN er en ASCII-kode som er oppgitt i oktalt-format.

Eksempel på bruk:

[david@nittedal david]$ echo -e '\a'

Gir en terminallyd.

[david@nittedal david]$ echo -e '\v'

Gir en vertikal tab.

[david@nittedal david]$ echo -e '\111'

Gir deg en stor "I" på skjermen.

Kjører du Bourn-skall, vil disse kodene virke med echo-kommandoen:

\b et tegn til venstre (backspace)

\c tar ikke linjeskift

\f sideskift (formfeed)

\r retur (carriage return)

\v vertikal tabulator

\t horisontal tabulator

\n hvor n er et oktalt nummer

Ønsker du et større utvalg terminalkoder, kan du bruke kommandoen tput. Denne kommandoen virker både under Bash-skall og Bourne-skall.

Syntaks: tput termkode

Termkode Funksjon

clear -renser skjermen (ren skjerm)

bel -klokkelyd fra terminalen

blink -blinking

dim -reduserer lysstyrken

smul -start av understreking

rmul -slutt på understreking

sgr0 -slår av alle koder

Eksempel på bruk:

[david@nittedal david]$ tput dim

Reduserer lysstyrken.

[david@nittedal david]$ tput clear

Setter opp en ren skjerm.

[david@nittedal david]$ tput sqr0

Slår av alle koder.

[david@nittedal david]$ echo "tput smul "Dette er tekst med understreking tput rmul"

Her skriver jeg ut en tekst med understreking.

Eksempler på variabler og utskriftsstyring rediger

Kommandofilen info:

  1. !/bin/bash

echo "Dagens dato og tid : \c"

date

echo "Antall brukere : \c"

who | wc -l

echo "Min personlige status : \c"

who am i

Kommandofilen info gir oss dagens tid, antall brukere og din personlige status. Først sendes tekst til skjermen med echo-kommandoen. Koden \c forhindrer linjeskift. Resultatet av date-kommandoen plasseres på samme linje.

Kommandofilen info1:

  1. !/bin/bash

TID="Dagens dato og tid : \c"

BRUKER="Antall brukere : \c"

MEG="Personlig status : \c"

echo "$TID"

date

echo "$BRUKER"

who | wc -l

echo "$MEG"

who am I

Kommandofilen info1 gjør akkurat det samme som info, men her definerer jeg først tre tekstvariabler. Disse variablene brukes igjen senere i echo-kommandoene.

Betingelseskommandoer rediger

Skallene har forskjellige logiske kontrollstrukturer. Jeg vil her gå igjennom de viktigste. Syntaksen er basert på sh-skall, som er veldig analogt med bash. I csh og tcsh er prinsippene de samme, men syntaksen noe forskjellig. Vil du programmere under andre skall, må du bruke man-sidene. Skallprosedyrer tar ofte for seg argumenter i en sløyfe og utfører betingede kommandoer for hvert argument. Sh-skallet har effektive hjelpemidler for flytkontroll. For eksempel for, case og while kan brukes i slike sammenhenger.

Kommandoene kan enten skrives direkte på skjermen eller kjøres i en kommandofil.

Test-kommandoen rediger

Man har et hjelpeprogram i Linux som returnerer en utgangsstatus, en verdi som kan brukes i forbindelse med betingelseskommandoer. Kommandoen test er bare til for å brukes av kommandofiler, den gir ikke noe annet resultat enn en utgangsstatus.

test -f fil

Returnerer utgangsstatus null (sann) hvis fil eksisterer, og utgangspunkt forskjellig fra null (usann) hvis fil ikke eksisterer. Her er noen av de mest brukte argumentene:

test -s fil sann hvis filen eksisterer og ikke er tom

   test -f fil sann hvis filen finnes og er en vanlig fil (i
       motsetning til en katalog eller driver) 

test -r fil sann hvis filen kan leses fra

test -w fil sann hvis filen kan skrives på

test -x fil sann hvis filen eksisterer og kan kjøres

test -d fil sann hvis filen er en katalog

test -n s1 sann hvis lengden på strengen (s1) er

   forskjellige fra null 

test -z s1 sann hvis lengden på strengen (s1) er lik null

test s1 = s2 sann hvis streng1 og streng2 er like

test s1! = s2 sann hvis streng1 og streng2 ikke er like

test s1 sann hvis s1 ikke er en null-streng

test n1 -eq n2 sann hvis heltallene n1 og n2 er like

test n1 -ne n2 sann hvis heltallene n1 og n2 ikke er like

test n1 -gt n2 sann hvis heltallet n1 er større enn n2

test n1 -ge n2 sann hvis heltallet n1 er større eller lik n2

test n1 -lt n2 sann hvis heltallet n1 er mindre enn n2

test n1 -le n2 sann hvis heltallet n1 er mindre eller lik n2

Til alle strengtestene anbefaler jeg bruk av anførselstegn. Og spesielt til test -z "s1", som ikke vil virke ellers.

Du kan også kombinere test med andre operatorer, for eksempel posisjonsparametere og expr-funksjonen.

Prøv eksemplet sjekkpass:

  1. !/bin/bash

if test $# -eq 0

then echo "Du må skrive inn et brukernavn!"

else grep $1 /etc/passwd

fi

I dette eksempelet har jeg brukt if-strukturen. Jeg har brukt test og posisjonsparameteren $#. Det blir testet om vedkommende som startet kommandofilen, har spesifisert noen argumenter. Hvis ingen argumenter er spesifisert, sendes echo-strengen til skjermen. Har du spesifisert argument, søkes det etter dette i /etc/passwd.

For-strukturen rediger

Med for-kommandoen kan du utføre en mengde operasjoner på hver fil, eller du kan utføre en kommando med flere argumenter. Den generelle notasjonen for en for-løkke er:

for variabel in ordliste

do

kommandoliste

done

Ordliste kan være en liste over variabler eller strenger som er separert med mellomrom. Kommandoene blir utført for hver enkel streng i ordlisten. Prøv eksemplet utskrifttall:

  1. !/bin/bash

for i in ls

do

pr -f $i | lpr;

done

Her tar jeg utskrift av alle filene i den katalogen jeg står i. Ordlisten vår her er ls-kommandoen som gir oss alle filene i den katalogen hvor kommandofilen blir startet. Hver enkel fil blir plassert i $i, formatert med pr-kommandoen og videresendt til skriver. Kommandoen pr er en Linux-formateringskommando. Utelater du ordlisten, kan du bruke samme kommando på alle argumenter, da benyttes bestemte posisjonsparametere som argument. Kommandofilen sjekketter:

  1. !/bin/bash

for i

do grep $i *.c

done

Prøv så:

sjekketter 'hash(`insert'

Alle c-filer med endelsen .c i den katalogen hvor kommandofilen sjekketter ble startet, blir her sjekket om de har tekststrengen hash(`insert.

Case-strukturen rediger

Notasjonen case gjør det mulig å hoppe til forskjellige steder i programmet; en tilsvarende kommando finner du i alle moderne programmeringsspråk. Den generelle syntaksen er:

case ord in

mønster1) kommandoliste1;;

mønster2) kommandoliste2;;

...

esac

Kommandofilen sammenligner ord mot alle mønstrene i case-setningen helt til den finner et ord som er identisk med et mønster. Hvis ordet er identisk med mønster1, vil kommandoliste1 utføres. Er ordet identisk med mønster2, vil kommandoliste2 utføres, osv. Hvis ordet ikke er identisk med noen av mønstrene, blir ingen av kommandolistene utført i casestrukturen.

fungerer som avslutning av case-løkken
avslutter hver kommandoliste

Bare ett mønster trenger å være identisk med ordet. Jeg får da et hopp ut av løkken, og de neste mønstersjekkene blir ikke utført.

Følgende eksempel kaller jeg case-valg:

  1. !/bin/bash

case $1 in

1) who;;

2) finger;;

3) who am i;;

0) exit;;

esac

Case-løkken bruker her den første posisjonsparameteren ($1) som variabel. Ønsker du å prøve, kan du for eksempel skrive:

[david@nittedal david]$ casevalg 3

Kommandoen who am i vil da bli utført.

Variabelen ord kan bare være identisk med ett mønster. Er * det første mønsteret, slår strengen alltid til der og ingen andre steder.

case $i in

  • .c) cc $i
  • .h | *.sh)

echo "Slapp av"

  • ) echo "$i ukjent type"

esac

Her har jeg et eksempel på flere alternative mønstre. De forskjellige alternativene er atskilt med kombineringskommandoen |. Les mer om dette i kapittel 9 og i avsnittet "Funksjoner og prosedyrer" i dette kapitlet.

If-strukturen rediger

Den enkleste if-kommandoen har følgende form:

if kommandoliste

then kommandoliste

fi

Kommandoen eller kommandolisten som kommer etter if, blir utført. Dette er i de fleste tilfellene en test. Hvis den er sann (0=sann), så utføres kommandoen eller kommandolisten etter then. Slutten på if-testen markeres med fi.

Hvis du vil ha utført kommandoer når if-testen ikke er sann, kan du bruke else-setningen:

if kommandoliste

then kommandoliste

else kommandoliste

fi

Her har jeg et eksempel jeg kaller sjekkpass:

  1. !/bin/bash

for i

do

if grep $i /etc/passwd

then

echo "$i er definert i /etc/passwd"

else

echo "$i er ikke definert i /etc/passwd"

fi

done

Eksempel på bruk:

sjekkpass david

david:*:200:100:Tech. Writer:/usr/david:/bin/csh

david er definert i /etc/passwd

Kommandofilen filet:

  1. !/bin/bash

for FILE

do

echo $FILE er:

if test -r "$FILE"; then

echo " lesbar,"

fi

if test -w "$FILE"; then

echo " skrivbar,"

fi

if test -f "$FILE"; then

echo " en normal fil,"

fi

if test -d "$FILE"; then

echo " en katalog,"

fi

if test -s "$FILE"; then

echo " og består av mer enn 0 tegn."

else

echo " og består av 0 tegn."

fi

done

exit 0

Kommandofilen filet sjekker hva slags fil jeg har. Dette eksemplet illustrerer også hvor viktig test-rutinen er.

Kommandofilen passgruppe:

  1. !/bin/bash

BB=/dev/null

for NAME in $@; do

if grep $NAME /etc/passwd > $BB 2>$BB; then

echo $NAME finnes i passord fil

else

if grep $NAME /etc/group >$BB 2>$BB; then

echo $NAME finnes i gruppe filen

else

echo $NAME finnes hverken i

echo passord eller gruppe fil

fi

fi

done

Kommandofilen passgruppe forventer et brukernavn. Finnes brukernavnet i /etc/passwd eller /etc/group, blir det gitt beskjed om det. Variabelen BB blir først definert som /dev/null. Det vil si at BB er det samme som en driver som sender alt ut i det tomme intet. Flere if-strukturer blir brukt for å finne ut om brukernavnet bare finnes i /etc/passwd, bare i /etc/group, eller i begge filene.

While-strukturen rediger

While blir brukt til å lage sløyfer. Den har følgende form:

while kommandoliste

do

   kommandoliste 

done

For hver runde i sløyfen utfører while kommandolisten som hører til den selv, og hvis siste kommando på listen returnerer en status forskjellig fra null, blir kommandolisten etter do utført. I motsatt fall avsluttes sløyfen.

Kommandofilen innlesbar:

  1. !/bin/bash

while test -r *

do

ls -la *

done

Innlesbar lister alle filer som kan leses.

Følgende eksempel kaller jeg kopipar:

  1. !/bin/bash

while test "$2" != ""; do

cp $1 $2

shift; shift

done

if test "$1" != ""; then

echo "$0: ulikt antall argumenter!"

fi

Kommandofilen kopipar har som oppgave å kopiere filpar. Denne kommandofilen bruker skallkommandoen shift, som er beskrevet i avsnittet "Flere kommandoer" i dette kapitlet.

Eksempel:

[david@nittedal david]$ kopipar fil1 fil2 fil3 fil4

Vil kopiere fil1 til fil2, og fil3 til fil4.

Until-løkken rediger

While-strukturen går i sløyfen så lenge kommandolisten er sann (status=0). Until-løkken går bare så lenge kommandolisten er usann. Når kommandolisten er sann (status=0), hopper programmet ut av strukturen.

Følgende eksempel kaller jeg inntil.test:

  1. !/bin/bash

until test -f datafil

do

sleep 1000

done

Strukturen går i en løkke helt til filen datafil blir opprettet. Jeg tester for hver 1000 tidsenhet, det vil si ca. hvert 500 sekund.

Flere kommandoer rediger

Posisjonsparametere og shift-kommandoen rediger

Når en kommandofil blir startet, skaper skallet automatisk posisjonsparameterne. Navnet på selve kommandofilen får variablen $0, mens det første argumentet blir satt til $1, det neste til $2, osv. til $9. Det ligger dermed en begrensning på ni posisjonsparametere.

Med skift-kommandoen kan jeg overkomme denne begrensningen. Skift-kommandoen flytter argumentene en posisjon til venstre.

Verdien til $1 blir kastet bort. $1 får dermed det som er plassert i $2, og $2 får det som var plassert i $3, osv.

Kommandofilen echoskift:

  1. !/bin/bash

while test $# !=0

do

echo $1 $2 $3 $4 $5 $6 $7 $8 $9

shift

done

Hver gang en ny runde i while-strukturen blir gjennomført, skifter argumentene plass én gang. Eksempel med kommandofilen echoskift:

echoskift a b c

a b c

b c

c

Følgende kommandofil kan brukes til å lese tolv navn:

  1. !/bin/bash

teller=1

while test $teller -le 12

do

echo "Navn : $1"

shift

done

NB! Du kan tvinge posisjonsparameterne i bestemte variabler $1 til $9 når du bruker set-kommandoen.

Break og continue rediger

Ved hjelp av kommandoen break kan du avbryte en for- eller while-løkke. Ønsker du å hoppe ut av strukturen bare i den omgangen du er inne i for øyeblikket, bruker du kommandoen continue. Både break og continue brukes mellom kommandoene do og done.

Har du flere løkker inni hverandre, vil break bare avslutte den innerste løkken. Ønsker du å gå ut av flere løkker, kan du bruke break n, hvor n er løkkenivået. Ettersom continue også bare påvirker den innerste løkken, må du bruke continue n hvis du skal avbryte flere løkker.

  1. !/bin/bash

while true

do

echo "Skriv inn data"

read inndata

case "$inndata" in

"done") break

"")

continue

  • )

echo "Hei"

esac

done

While true er en evig løkke. Skriver du teksten break, går programmet helt ut av strukturen. Trykker du bare på Enter-tasten, går programmet til begynnelsen av løkken, og inndata leses på nytt. Skriver du navnet ditt eller noe annet, blir teksten "hei" sendt til skjermen.

Kommandoen exit rediger

Med exit-kommandoen er det mulig å sende positive eller negative meldinger. Statusverdi 0 (null) gis ved feilfri utføring av en kommando, ellers blir statusverdien forskjellig fra null. Exit-kodene kan brukes som kommunikasjon mellom skallene.

Kommandoen exit simulerer en avslutning på en kommandofil. En kommandofil kan derfor termineres normalt ved å plassere exit 0 som siste linje i filen.

Kodebeskrivelse:

0 - feilfri utføring 1 - kommandofeil

2 - syntaksfeil 3 - får ikke tak i avbruddsignalet

Eksempel på bruk:

  1. !/bin/bash

if test $# -lt 2

then

echo "To eller flere argumenter må jeg ha";exit 1

fi

Her tester jeg antall argumenter brukeren har skrevet. Hvis brukeren har spesifisert mindre enn to argumenter, hopper programmet ut med exit.

  1. !/bin/bash

if grep $var ordreliste

then

exit 0

else

echo "Ikke i ordreliste"

exit 1

fi

Her har jeg en test som gir enten exit 0 eller exit 1.

Gruppering av kommandoer rediger

I et skall finnes det to forskjellige måter å gruppere kommandoer på:

a) Du kan bruke vanlige parenteser "( "og ")". Når du bruker disse, skaper du et subskall som leser gruppen av kommandoer. Venstre- og høyreparenteser kan plasseres fritt på linjen.

b) Du kan også få hjelp av { og }. Det dannes ikke noe subskall, men de grupperte kommandoene leses direkte av skallet. Jeg bruker gruppering med { og } når standard utdata skal brukes som standard inndata til en kommando.

Eksempel:

[david@nittedal david]$ (date; who | wc -l) >> datafil

Først blir kommandoen date utført, deretter teller jeg antall brukere pålogget. Begge resultatene blir addert til datafil.

[david@nittedal david]$ (gcc -o calc calc.c; strip calc; mv calc regn) &

Her gjør jeg en kompilering og stripping av filen, og jeg skifter navn på filen calc til regn. Alle operasjonene går i bakgrunnen.

Jeg kan midlertidig flytte til en bestemt katalog og utføre en kommando på to måter:

[david@nittedal david]$ katalog='pwd'; cd /prog/c-kode/cf.d

[david@nittedal david]$ ./make_device; cd $katalog

eller

[david@nittedal david]$ (cd /prog/c-kode/cf.d; ./make_device)

I begge disse eksemplene gjøres det samme, men i det siste eksemplet har jeg opprettet et subskall. Jeg blir derfor plassert i min opprinnelige katalog.

[david@nittedal david]$ cp /etc/passwd /usr/david/passwd

[david@nittedal david]$ (cd /etc; cp passwd /usr/david/passwd)

I første linje kopieres filen /etc/passwd til /usr/david/passwd. I det andre eksemplet skifter jeg først til katalogen /etc, og deretter kopieres filen. Begge kommandolinjene har samme effekt.

[david@nittedal david]$ {ls /dev; ls /dev/fd} | tr [a-z] [A-Z]

Her blir alle filene i /dev og /dev/dsk standard inndata til tr-kommandoen.

Kommandoer i variabler

Alle kommandoer kan defineres i en variabel. Det eneste du må huske på, er å omslutte innholdet med apostrofer. Jeg kaller dette kommandosubstitusjon. En kommando som er avgrenset med apostrofer, blir utført av skallet; deretter erstatter et nytt skall kommandouttrykket. For eksempel:

[david@nittedal david]$ dato='date'

Her blir date-kommandoen plassert i skallvariabelen dato. Ønsker du å skrive ut variabelen dato, skriver du bare:

[david@nittedal david]$ echo $dato

Jeg kan avgrense flere kommandoer med apostrofer, for eksempel:

[david@nittedal david]$ antallfiler='ls | wc -l'

Antall filer blir plassert i variabelen antallfiler. Se også avsnittet "Variabler" i dette kapitlet.

Reserverte tegn rediger

Her er en oppsummering av operatorer og uttrykk som kan brukes i en kommandofil.

Det har kommet noen nye reserverte ord. For repetisjon kan du lese kapittel 9, som tar for seg omdirigering, rør og filtre. Jokere er tatt opp i kapittel 6.

Referanser og definering av variabler er tatt opp i begynnelsen av dette kapitlet.

Reserverte ord

   | rør
   && og-hvis-symbol (Hvis du skriver to kommandoer med && imellom, utføres den siste bare hvis den første gikk bra.) ||
   eller-hvis-symbol (Hvis du skriver to kommandoer med || imellom, utføres den siste bare hvis den første feilet.) ; skiller kommandoer ;; avslutter case-løkke
   & bakgrunnsprosessering () grupperer kommandoer med subskall { } grupperer kommandoer uten subskall
   < omdirigering av standard inndata
   << here-dokument
   > omdirigering av standard utdata
   >> legger til standard utdata # kommentar i bash- og sh-kommandofiler 

&& og || er veldig nyttige når du skal teste flere ting på en gang, for eksempel if test -z “foo" && test -n “bar".

Mønstre (Jokere)

  • erstatter ett eller flere tegn

? erstatter ett tegn

[...] enkelttegn eller tegnintervall

Substitusjon

$n bytter skallvariabler

p... utfører et program på linje

Referanse

   \ tolker neste tegn som tekst 
   '...' innleder og avslutter streng (tolktegnene) "..." innleder og avslutter streng (tolktegnene
       utenom $'\") 

Definere variabler

   navn="streng" $navn har strengverdien 

Here-dokument rediger

I stedet for å ha egne datafiler kan du samle data i en kommandofil. Dette brukes ved here-dokument.

for i

do

grep $i <<s

123.45 Oslo

124.50 Trondheim

156.60 Bergen

124.56 Stavanger

s

done

I eksemplet ovenfor tar skallet teksten mellom << og s som standard inndata for kommandoen grep. Jeg har valgt tegnet s for avslutning av fil. Du står helt fritt til å velge avslutningstegn.

Funksjoner og prosedyrer rediger

Alle programmeringsspråk har både innebygde funksjoner og muligheten til å definere funksjoner. Prosedyrer gjør at jeg kan dele opp programmer i mindre deler. Grupper av kommandoer som gjentas flere steder, trenger heller ikke å redefineres.

Innebygde funksjoner - expr rediger

Det finnes en innebygd funksjon (kommando) som heter expr. Den bruker du når du skal foreta beregninger. Med expr kan du foreta matematiske beregninger på skallvariabler. Følgende operatorer kan brukes i expr:

+ addisjon

- subtraksjon

  • multiplikasjon

/ divisjon

% rest

Operatorer og operand har forskjellige argumenter til expr. Jeg må derfor ha et mellomrom mellom de forskjellige variablene.

Kommandofilen multi:

expr $1 * $2

Eksempel:

[david@nittedal david]$ multi 8 4

32

Kommandofilen pluss:

expr $1 + $2 + $3 + $4

Eksempel på bruk:

[david@nittedal david]$ pluss 2 3 6 7

18

Definere funksjoner rediger

I skallet kan du definere funksjoner. Definerte funksjoner er analogt med prosedyrer, med det unntaket at funksjoner er i maskinens minne, mens prosedyrer ligger på disken som en separat kommandofil (program). Funksjoner blir dermed utført av skallets prosess, mens prosedyrer blir utført som en separat prosess.

Syntaksen for definerte funksjoner er:

navn () {

kommandoliste;

}

Du må definere et navn på funksjonen og lage en kommandoliste. Kommandolisten begynner på { og avsluttes med }.

En funksjon kan kalles opp så ofte du vil. Her har jeg et eksempel på en enkel funksjon:

standard_tekst ()

{

echo "*********************************************"

echo " IDG Norge Books AS "

echo "*********************************************"

}

Denne funksjonen kan du bruke hvor du vil i kommandofilen. Du kaller opp funksjonen ved å skrive navnet på funksjonen, i dette tilfellet standard_tekst.

Her har jeg et eksempel på en funksjon som leser om jeg skriver ja eller nei:

hent_ja_nei ()

while echo -n "$* (J/N)?" >& 2

do

read ja_nei

case $ja_nei in

[jJ]) return 0

[nN]) return 1

  • ) echo "Svar ja eller nei" >& 2

esac

done

}

Denne funksjonen legger til teksten (J/N) til standard utdata. Funksjonen godtar bare J, j, N, n som input og returnerer en kode 0 eller 1. Hvis inputen fra brukeren er noe annet, sender funksjonen teksten "Svar ja eller nei". Løkken er evig hvis brukeren ikke svarer J, j, N eller n.

Eksempel på start av funksjonen hent_ja_nei:

hent_ja_nei " Skal jeg avbryte kommandofil" || exit

Prosedyrer = rediger

Du lager en prosedyre som en separat kommandofil og setter på x-bitet. Deretter kaller du opp prosedyren fra hovedkommandofilen. Prosedyren er egentlig bare en vanlig kommandofil.

Husk at hovedprogrammet og prosedyrene bør ligge i samme katalog. Hvis de ikke gjør det, må søkebanen være riktig satt opp.

Eksempel:

Her lager jeg en prosedyre som jeg kaller brev_til_alle:

brev=$1

shift

for i in $*

do mail $i < $brev

done

I hovedprogrammet kan jeg kalle opp prosedyren med for eksempel:

[david@nittedal david]$ brev_til_alle rapport ole nils per

Kan du lage en kommandofil, er det enkelt å lage prosedyrer.

Skall-miljøet rediger

Felles oppstartsfil for alle bash-brukere er /etc/profile. Denne filen kan bare settes opp av systemadministrator. Som standard innloggingsfil for de enkelte brukerne, brukte man tidligere $HOME/.profile. Denne konfigurasjonsfilen er nå forlatt men brukes fortsatt av blant annet Bourne-skall (sh). Filen $HOME/.profile blir bare utført en gang dvs. når du logger inn på systemet. Den tilsvarende filen under bash-skall er $HOME/.bash_profile. Denne filen blir bare utført når du logger inn første gang som bash-bruker. Hver gang du logger inn eller starter et skall blir innloggingsfilen $HOME/.bashrc utført.

Variabler i både $HOME/.bash_profile og $HOME/.bashrc blir eksportert til alle barn av hovedskallet. Ønsker du å endre miljøparametere, må du endre på enten $HOME/.bash_profile eller $HOME/.bashrc. Det er ikke nødvendig å logge deg inn og ut hvis du har gjort endringer på systemfilene. Skriv bare .bash_profile eller .bashrc fra systemledeteksten.

Skallets utføringsflagg rediger

Med set-kommandoen kan jeg også endre skallets utføringsflagg (opsjoner) ved å sette forskjellige flagg.

    {attachment:Ramme48.png}  De mest brukte flaggene er -x og -v. De brukes ofte ved feilsøking av kommandofiler. For eksempel: 

[david@nittedal david]$ set -x

[david@nittedal david]$ set -v

De to flaggene har følgende betydning:

   -v Standard inndata blir skrevet ut etter hvert som de blir lest av skallet. Dette flagget brukes mest for å isolere feil.
   -x Kommandoer og dets argumenter blir skrevet ut etter hvert som de blir utført. Skallkommandoer som for, while osv. blir ikke skrevet ut. 

Det er viktig å merke seg at -x bare lager en trace av de kommandoer som blir utført, mens -v skriver ut hver linje.

Ønsker du å skru av disse flaggene, skriver du set +x eller bare set -.

Du kan bruke flaggene direkte, uten å bruke set-kommandoen først. Sett da bare opsjonen foran sh-skallet. For eksempel:

[david@nittedal david]$ bash -x batchfil

Skallets miljø rediger

Alle variabler og deres verdier som er gitt ved kjøring av en kommandofil/kommando, utgjør skallets miljø (environment=env). Miljøet inkluderer variabler som kommandofilen arver fra foreldreprosessen. Nøkkelparametere som en kommandofil blir startet med, er selvfølgelig en del av miljøet til kommandofilen.

Variablene som et skall plasserer i en barneprosess, er de som har blitt eksportert med export-kommandoen. Kommandoen export plasserer de spesifiserte variablene i både moderskallet og i andre barneprosesser av moderskallet.

En prosedyre kan få tilgang til en hvilken som helst variabel som er definert i dens miljø. Hvis en kommandofil endrer på en miljøparameter, gjelder denne endringen bare lokalt for denne prosedyren og ikke globalt for skallet. Skal endringen gjøres globalt for skallet, må variabelen eksporteres. Det gjøres ved å skrive export og variabelnavn.

Miljøvariabler ser du med env-kommando:

[david@nittedal david]$ env

BROWSER=/usr/bin/netscape

HISTSIZE=1000

HOSTNAME=nittedal.c2i.net

LOGNAME=david

HISTFILESIZE=1000

MAIL=/var/spool/mail/david

MACHTYPE=i386

TERMCAP=xterm|vs100|xterm terminal emulator (X11R6 Window System):am:km:mi:ms:xn

xo:co#80:it#8:li#24:AL=\E[%dL:DC=\E[%dP:DL=\E[%dM:DO…

WINDOWID=20971533

PWD=/tmp

SHLVL=5

_=/usr/bin/env

[root@nittedal /tmp]#

Eksempel med set:

[david@nittedal david]$ set

BASH=/bin/bash

BASH_VERSION=1.14.7(1)

BROWSER=/usr/bin/netscape

[root@nittedal /tmp]#

Med set får du også med spesielle bash-, sh-, zsh- og tcsh-variabler.

Et programeksempel rediger

Til slutt har jeg laget en kommandofil som tar opp de fleste bash-skall-kommandoene vi har gått igjennom.

  1. !/bin/bash

clear

while test "$answer" != "0"

do

clear

echo ""

echo " 1 - List files(directory) "

echo " 2 - Change catalog "

echo " 3 - File check "

echo " 4 - Copy file "

echo " 5 - Remove file "

echo " 6 - Change filename "

echo " 7 - Output file to screen "

echo " 8 - Output file to printer"

echo " 9 - Users logged in to the computer"

echo " 10 - Who am i"

echo " 11 - Current directory"

echo " 12 - Make a directory"

echo " 13 - Delete empty directory"

echo " 14 - Quit the menu"

echo ""

echo -n " Choose a function (1/../14) and press <RETURN> key :"

read answer

cd $home

  1. 1 - List files(directory)

if test "$answer" = "1";then

   clear echo "" echo "Current/working directory is :" pwd echo "" echo "List files and directories" ls -la | more echo ""
   echo -n "Press <RETURN> to continue :" read stop 

fi

  1. 2 - Change directory

if test "$answer" = "2";then

   clear echo "" echo -n "Current/working directory :" pwd echo "" echo "To continue in current/working directory answer with 

'.'(period) and press <RETURN>"

   echo "If you want to move one level up, answer with 

'..'(two periods) and press <RETURN>"

   echo ""
   echo "If you want to move back to your own home-directory you only need to press <RETURN>" echo ""
   echo "If you want to move to a child-directory just write the name of the directory and press <RETURN>" echo "" echo -n "Which directory would you like to use :" read dir cd $dir echo "" echo -n "New active directory is :" pwd echo ""
   echo -n "Press <RETURN> to continue :" read stop 

fi

  1. 3 - File check

if test "$answer" = "3";then

   clear echo "" echo -n "Which file do you wish to check :" read file if test -d "$file";then
       echo "" echo " "$file" is a directory" echo ""
       echo -n "Press <RETURN> to continue :" read stop 
   fi if test -r "$file";then
       echo "" echo "We can read the file" 
   fi if test -w "$file";then
       echo "" echo "We can write to the file" 
   fi if test ! -f "$file";then
       echo "" echo ""$file" is not a sub-directory or a file in the specified directory" 
   fi echo ""
   echo -n "Press <RETURN> to continue :" read stop 

fi

  1. 4 - Copy file

if test "$answer" = "4";then

   clear echo "" echo "" echo -n "You are now placed in directory :" pwd echo "" echo -n "Which file do you want to copy :" read fromfile echo "" if test -s "$fromfile";then
       echo -n "Which directory/file would you like to copy to :" read tofile if test ! -s "$tofile";then
           cp "$fromfile" "$tofile" 
       else
           echo "" echo -n ""$tofile" exist do you want overwrite (y/n) :" read yes if test "$yes" = "y";then
               cp "$fromfile" "$tofile" 
           fi 
       fi 
   else
       echo ""
       echo -n ""$fromfile" do not exist - press <RETURN> :" read stop 
   fi 

fi

  1. 5 - Delete file

if test "$answer" = "5";then

   clear echo "" echo -n "Which file do you want to delete :" read file if test -f "$file";then
       clear echo "" echo -n ""$file" exists. Do you really want to delete the file (y/n) :" read yes if test "$yes" = "y";then
           rm $file 
       fi 
   else echo ""
       echo -n ""$file" do not exists - press <RETURN>" read stop 
       fi 

fi

  1. 6 - Change name on file

if test "$answer" = "6";then

   clear echo "" echo -n "You are now in directory :" pwd echo "" echo -n "Which filename would you like to change :" read file if test -f "$file";then
       clear echo "" echo -n ""$file" exists. Please give a new name :" read newname if test ! -f "$newname";then
           mv "$file" "$newname" 
       else
           echo ""
           echo -n ""$newname" exists - press <RETURN> :" read stop 
       fi 
   else
       echo ""
       echo -n ""$file" do not exists - press <RETURN> :" read stop 
   fi 

fi

  1. 7 - Output file to monitor screen

if test "$answer" = "7";then

   clear echo ""
   echo "If the file is more than one page you may continue by pressing the <RETURN> key" echo "" echo -n "Which file would you like to see on your monitor screen :" read file if test -s "$file";then
       more "$file" echo ""
       echo -n "Press <RETURN> to continue :" read stop 
   else
       echo "" echo "The file do not exists or is empty" 
   echo ""
       echo -n "Press <RETURN> to continue :" read stop 
   fi 

fi

  1. 8 - Output file to printer

if test "$answer" = "8";then

   clear echo "" echo -n "Which file would you like to print :" read file echo "" lpr $file 
   echo "" 

fi

  1. 9 - Users logged on the system

if test "$answer" = "9";then

   clear echo "" echo -n "Please, wait....."
       who > /tmp/who-list clear echo "" echo "Active users logged on the system :" echo "" 
   cat /tmp/who-list echo ""
       echo -n "Number of users logged on the system :" 
   cat /tmp/who-list | wc -l echo ""
       echo -n "Press <RETURN> to continue:" read stop 

fi

  1. 10 - Who am I

if test "$answer" = "10";then

   clear echo "" echo -n "I am user :" whoami echo ""
   echo -n "Press <RETURN> to continue :" read stop 

fi

  1. 11 - Current directory

if test "$answer" = "11";then

   clear echo "" echo -n "Current directory is :" pwd 
   echo ""
       echo -n "Press <RETURN> to continue :" read stop 

fi

  1. 12 - Make a directory

if test "$answer" = "12";then

   clear echo "" echo -n "Current directory is :" pwd echo " " echo -n "Is this the right directory - would you like to continue (y/n) :" read yes if test "$yes" = "y";then
       echo "" echo -n "What is the name of the new sub-directory :" read subdir if test ! -d "$subdir";then
           mkdir "$subdir" if test ! -d "$subdir";then
               echo "" echo -n ""$subdir" this directory do not exists :" read stop 
           fi 
       else
           echo ""
           echo -n ""$subdir" this directory do already exists - press <RETURN> :" read stop 
       fi 
   fi 

fi

  1. 13 - Delete empty directory

if test "$answer" = "13";then

   clear echo "" echo -n "Current directory is :" pwd echo "" echo -n "Which empty directory would you like to delete :" read file if test -d "$file";then
       cd $file echo "" echo "Checking directory" ls -la cd .. echo "" echo -n "Any files in that directory? - (y/n) :" read yes if test "$yes" = "y";then
           rmdir "$file" if test ! -d "$file";then
               echo ""
               echo -n ""$file" is deleted - press <RETURN> :" read stop 
           fi 
       fi 
   else
       echo ""
       echo -n ""$file" is not a directory - press <RETURN> :" read stop 
   fi 

fi

  1. 14 - Quit the menu

if test "$answer" = "14";then

   exit; 

fi

done

Oppgaver til kapittel 16 rediger

Oppgave 16.1

Lag en kommandofil som du kaller shell.1. Kommandofilen skal inneholde disse tre linjene:

echo "Hva heter du? "

read navn

echo "Hei $navn"

Utfør filen på de tre måtene som er mulig.

Oppgave 16.2

Lag en kommandofil som leser inn fornavn, etternavn, kjønn, høyde og vekt fra kommandolinjen. Når dataene er registert skal programmet skrive ut dataene med ledetekster. Kall kommandofilen for shell.2

Oppgave 16.3

Lag en kommandofil som gjemmer systemparameterne til din hjemmekatalog, skall og terminal i andre variabler. Disse nye variablene skal vises på skjermen. Kall kommandofilen for shell.3.

Oppgave 16.4

Hva gjør de neste tre kommandolinjene?

data='ls -la | grep "*.txt"'

(echo "Hva er navnet ditt"; read navn) || exit

{who; whoami; du;} | wc -l

Oppgave 16.5

Lag en kommandofil som skal kunne kalles opp på tre måter.

shell.4 list filnavn

shell.4 innhold filnavn

shell.4 print filnavn

Tips: (ls -la, cat, lpr -dskriver). Bruk case. Kommandofilen skal kalles shell.4.

Oppgave 16.6

a) Lag en kommandofil som viser følgende:

Dagens dato/klokke : Mon Apr 04 09:18:29 SCET 2005

Antall brukere : 2

Min status : david tty01 Apr 04 06:39

Min hjemmekatalog : /home/davide

Plassert i katalog : /home/davide/stk

Mine filer : total 10

drwxr-xr-x 2 david Support 64 Apr 04 09:18 .

drwxr-xr-x 8 david Support 416 Apr 04 08:37 ..

-rwxr--r-- 1 david Support 1220 Feb 22 06:21 stktore

-rw-r--r-- 1 david Support 305 Apr 04 09:18 test

Tips: (date, who, who am i, $home, pwd, ls -la | more)

b) Utvid kommandofilen med følgende. Det skal legges inn parametre som angir i hvilken katalog du ønsker å liste filene i. Du skal benytte deg av følgende regler:

   er det ikke spesifisert noen parametere, betyr det den katalogen brukeren står i.
   en parameter tolkes som katalog
   flere parametere skal gi feilmelding 

Oppgave 16.7

Hva gjør følgende kommandofil?

  1. !/bin/bash

for i in I D G N O R G E

do

echo "Skriv inn bokstavene $i"

echo -n "$i "

done

Oppgave 16.8

Lag et menysystem som gir brukeren muligheten til å definere terminaltype og starte forskjellige applikasjoner, for eksempel WordPerfect., StarOffice, sjakkprogram (xboard) etc. Det skal også være en egen opsjon for å avslutte.

Løsningsforslag

Oppgave 16.1

shell.1

sh shell.1

sh < shell.1

chmod u+x shell.1;shell.1

Oppgave 16.2

  1. !/bin/bash

echo -n "Angi fornavn: "

read fn

echo -n "Angi etternavn: "

read en

echo -n "Angi kjønn: "

read kj

echo -n "Angi høyde: "

read hd

echo -n "Angi vekt: "

read vk

clear

echo "Du er $kj og navnet ditt er $fn $en"

echo "Din høyde og vekt er $hd og $vk"

Oppgave 16.3

  1. !/bin/bash

homenavn=$HOME

shellnavn=$SHELL

termnavn=$TERM

echo "Din hjemmekatalog er :" $homenavn

echo "Ditt skall er :" $shellnavn

echo "Terminaltype er :" $termnavn

Oppgave 16.5

  1. !/bin/bash

case $1 in

list) ls -la $2;;

innhold) more $2;;

print) lpr -Pskriver1 $2;;

  • ) echo " Dette er ukjent?";;

esac

Oppgave 16.6 a)

  1. !/bin/bash

bind='---------'

echo -n "$bind" "Dagens dato og klokke: "

date

echo -n "$bind" "Antall brukere : "

who | wc -l

echo -n "$bind" "Min status : "

whoami

echo -n "$bind" "Min hjemmekatalog : "

echo $HOME

echo -n "$bind" "Plassert i katalog : "

pwd

echo -n "$bind" "Mine filer : "

ls -la | more

exit 0

Oppgave 16.6 b)

  1. !/bin/bash

bind='---------'

case $# in

0) katalog=pwd;;

1) katalog=$1;;

  • ) echo "Bruk: Spesifiserer bare en katalog"; exit 1;;

esac

echo -n "$bind" "Dagens dato og klokke: "

date

echo -n "$bind" "Antall brukere : "

who | wc -l

echo -n "$bind" "Min status : "

whoami

echo -n "$bind" "Min hjemmekatalog : "

echo $HOME

echo -n "$bind" "Plassert i katalog : "

pwd

echo -n "$bind" "Mine filer : "

ls -la $katalog | more

exit 0