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:
- !/bin/bash
- 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).
- !/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:
- !/bin/bash
echo "Diskforbruk"
du /home/elboth
Her får du blokkforbruket til /home/elboth.
Kommandofilen sendterm:
- !/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:
- !/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:
- !/bin/bash
ls /bin | sort
Sjekker filene i katalogen /bin og sorterer innholdet. (Du finner mer om sort-kommandoen i kapittel 13.)
Kommandofilen fcount:
- !/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:
- !/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:
- !/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:
- !/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:
- !/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:
- !/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:
- !/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:
- !/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:
- !/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:
- !/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:
- !/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:
- !/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:
- !/bin/bash
while test -r *
do
ls -la *
done
Innlesbar lister alle filer som kan leses.
Følgende eksempel kaller jeg kopipar:
- !/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:
- !/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:
- !/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:
- !/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.
- !/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:
- !/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.
- !/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.
- !/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 - 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
- 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
- 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
- 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
- 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
- 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
- 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
- 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
- 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
- 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
- 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
- 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
- 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
- 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?
- !/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
- !/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
- !/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
- !/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)
- !/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)
- !/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