Version 0.7.2
Denna bok finns tillgänglig på följande adresser:
Copyright © 1997,1998 Göran Andersson <goran@debian.org>
Copyright © 1998 Kalle Andersson <kalle.andersson@mbox303.swipnet.se>
Permission is granted to make and distribute verbatim copies of this manual provided the copyright notice and this permission notice are preserved on all copies.
Permission is granted to copy and distribute modified versions of this manual under the conditions for verbatim copying, provided that the entire resulting derived work is distributed under the terms of a permission notice identical to this one.
Varje person som använder en UNIX-dator har ett unikt namn, ett så kallat användarnamn. Det första man gör då man ska börja arbeta vid datorn är att tala om vem man är genom att skriva sitt användarnamn. Därefter måste man bevisa att man verkligen är den person man påstår genom att ange ett lösenord. Denna process, där man anger sitt användarnamn och sitt lösenord, kallas för inloggning. Innan man kan logga in på en viss dator måste man ha fått ett användarnamn och ett preliminärt lösenord av systemadministratören, den person som är ansvarig för skötseln av datorn. (Systemadministratören har användarnamnet root.) Det preliminära lösenordet bör man så snart som möjligt ändra till något som bara man själv känner till.
Det finns två olika sätt att logga in:
via en textterminal eller via fönstersystemet X
(se kapitel 4 för information om X).
I det förra fallet är skärmen i
textläge, och en markör blinkar efter orden
fafner login: (''fafner'' är datorns namn).
I det senare fallet ser det ut ungefär som i
figur 1.1.
Det finns oftast sex olika textterminaler att logga in genom.
Vissa UNIX-system har inte någon grafisk inloggningsskärm,
andra har en eller till och med flera.
Man kan växla mellan de olika
inloggningsskärmarna genom att hålla tangenterna
Ctrl och Alt nedtryckta och samtidigt trycka
på en av funktionstangenterna - F1 till F6
ger textterminaler medan F7, F8 osv
ger X-skärmar på de datorer som kör X.fafner login: göran
Lösenord:
$I exemplet ovan skrev datorn först ut texten
fafner login:, varefter jag angav
mitt användarnamn ''göran'' och tryckte på returtangenten.
Datorn frågade sedan efter mitt lösenord.
Lösenordet syns inte på skärmen då man skriver in det för
att ingen ska kunna se det ''över ens axel''.
Motsatsen till inloggning är utloggning. När man är klar med sitt arbete vid datorn och inte tänker använda den igen på ett tag, så kan man logga ut med kommandot logout.
Vad som sker efter inloggningen
beror på hur systemet är
inställt. Även om man inte loggar in via fönstersystemet X,
så kanske X startas automatiskt då man loggat in.
I vilket fall som helst
startas förmodligen en kommandotolk, genom vilken man kan
ge datorn instruktioner. Datorn visar att den är redo för ett nytt
kommando genom att skriva ut den så kallade prompten, som
fortsättningsvis anges med ett dollartecken.
Man kan konfigurera många av
inställningarna i UNIX, dvs ändra dem så att de passar en själv bättre.
Detta gäller även prompten, så hur den faktiskt ser ut varierar starkt
från system till system. Andra vanliga sätt att ange prompten är
till exempel som # eller som fafner>.
Låt oss som första exempel ta kommandot passwd, som
man använder för att byta lösenord. Man skriver kommandot vid
prompten, och trycker sedan på returtangenten:$ passwd
Nuvarande lösenord:
Nytt lösenord:
Upprepa det nya lösenordet:
Lösenordet har ändrats.
$Inte heller nu återges lösenordet på skärmen när man skriver in det.
Detta innebär en viss risk för att man råkar skriva fel utan att upptäcka
det, så för att vara på den säkra sidan får man upprepa det nya lösenordet
innan det ändras. Dessutom måste man först bevisa att man kan
det gamla lösenordet.
I det här sammanhanget kan det vara värt att nämna att UNIX ibland
kan vara tämligen kärvt; kommandonamn är ofta kryptiska
förkortningar som passwd i stället för password,
som cp i stället för copy och, det kanske värsta
exemplet, umount i stället för unmount. Detta tilltalar
rutinerade användare, som kan skriva sina kommandon snabbare tack
vare att det blir färre tangentnedslag,
men kan upplevas som frånstötande eller svårtillgängligt av nybörjare.
(Denna brist på inställsamhet kommer sig bland annat av
att UNIX skapades innan datorer fanns i varje hem och
operativsystem blev kommersiella massprodukter.)
Om man inte är nöjd med hur ett visst kommando skrivs,
så kan man dock ändra det genom att ange ett alias för kommandot:$ alias lösenord=passwd
$ lösenord
Nuvarande lösenord:
Vilken fantastisk känsla det är att vara
inloggad på ett UNIX-system! Låt oss genast prova några
kommandon. Vad är klockan nu?$ date
tis sep 2 15:13:52 CEST 1997
$Klockan är alltså snart kvart över tre.
Ovan står ''CEST'' för centraleuropeisk sommartid.
Vi kan få almanackan utskriven med hjälp av
kommandot gcal. Men det
räcker inte att skriva gcal; vi måste också tala om
vilken månad och vilket år det gäller. Dessa upplysningar
anges efter gcal. De ska separeras med ett eller
flera mellanslag. Sådana ''ord'' kallas för argument till
kommandot.$ gcal 1 2000
januari 2000
måndag 3 10 17 24 31
tisdag 4 11 18 25
onsdag 5 12 19 26
torsdag 6 13 20 27
fredag 7 14 21 28
lördag 1 8 15 22 29
söndag 2 9 16 23 30
Ett lustigt litet kommando, echo, har som enda funktion
att upprepa sina argument. Detta kan tyckas meningslöst,
men vi ska senare se att kommandot kan vara mycket användbart.$ echo hejsan svejsan
hejsan svejsan
$
Kommandot man program ger en bruksanvisning
för kommandot program.$ man passwd
PASSWD(1) PASSWD(1)
NAME
passwd - change user password
SYNOPSIS
passwd [-f|-s] [name]
passwd [-g] [-r|R] group
passwd [-x max] [-n min] [-w warn] [-i inact] name
passwd -l|-u|-d|-S name
DESCRIPTION
passwd changes passwords for user and group accounts. A
normal user may only change the password for their own
account, the super user may change the password for any
account. The administrator of a group may change the
password for the group. passwd also changes account
information, such as the full name of the user, their
login shell, or password expiry dates and intervals.
Password Changes
The user is first prompted for their old password, if one
is present. This password is then encrypted and compared
against the stored password. The user has only one chance
to enter the correct password. The super user is permit-
ted to bypass this step so that forgotten passwords may be
changed.Detta är inledningen av bruksanvisningen till passwd.
För att se mer av den ska man trycka på mellanslagstangenten,
för att avsluta ska man trycka på q.
(I UNIX barndom var man den viktigaste informationskällan
för samtliga kommandon, men så är det inte längre. Andra, modernare
former att presentera bruksanvisningar håller på att ta över.
Symptomatiskt nog har ingen ännu brytt sig om att översätta
dessa bruksanvisningar till svenska.)
Vissa kommandon ger en kort introduktion till sig själva
om man anropar dem
med -h eller --help som argument.
(Ett sådant argument, som inte ger mer information till kommandot
utan modifierar dess verkan, kallas för en flagga. Flaggor består
vanligtvis av ett streck följt av en bokstav eller två streck följt av
ett ord.)$ date --help
Användning: date [FLAGGA]... [+FORMAT]
eller: date [FLAGGA] [MMDDhhmm[[ÅÅ]ÅÅ][.ss]]
Visa aktuell tid på angivet FORMAT, eller ställ systemklockan.
-d, --date=STRÄNG visa tid som beskrivs av STRÄNG, inte "nu"
-f, --file=DATUMFIL samma som --date en gång per rad i DATUMFIL
-r, --reference=FIL visa när FIL senast modifierades
-R, --rfc-822 skriv ut RFC-822-kompatibel datumsträng
-s, --set=STRÄNG sätt tiden enligt STRÄNG
-u, --utc, --universal skriv ut eller sätt Coordinated Universal Time
--help visa denna hjälptext och avsluta
Det vanliga är att en rad innehåller exakt ett kommando,
men man kan skriva flera kommandon på samma rad om de separeras
med semikolon. Likaså kan det inträffa att ett kommando är flera rader
långt. Om man skriver ett bakvänt snedstreck i slutet av en
kommandorad, så tolkas det som att kommandot fortsätter på
nästa rad. Man får då en ny prompt (som kan se annorlunda ut än den
vanliga) så att man kan skriva färdigt kommandot.$ echo Dagens datum är ; date
Dagens datum är
tis sep 2 16:44:29 CEST 1997
$ echo Detta är ett mycket \
> långt kommando
Detta är ett mycket långt kommando
$När man separerar två kommandon med semikolon som ovan, så
fungerar det precis som om man hade gett det första
kommandot, sedan tryckt retur och till slut gett det andra
kommandot. Det andra kommandot kör alltså inte igång förrän det första
är klart.
När man ska skriva in ett kommando, befinner man sig i en enkel textredigerare som hanterar endast en rad i taget. Denna textredigerare heter Readline. I det här avsnittet ska vi beskriva hur Readline fungerar.
De viktigaste Readline-kommandona återges i tabell 1.1. Där det står tex C-a menar vi att man ska man trycka ned kontrolltangenten, hålla den nedtryckt och samtidigt trycka a. Med M-f menas att man ska hålla metatangenten nedtryckt och samtidigt trycka på f. Kontrolltangenten ser troligtvis ut som Ctrl och metatangenten som Alt. Om man inte finner metatangenten, eller om den inte fungerar som den ska, så kan man som ersättning för denna trycka och släppa tangenten Esc. Med C-M-s menas att man ska hålla kontroll- och metatangenterna nedtryckta, och samtidigt trycka på s.
Den översta delen av tabell 1.1 visar hur man flyttar markören. Man går ett steg bakåt med C-b och ett steg framåt med C-f. Det är lätt att komma ihåg dessa kommandon eftersom de använder bokstäverna ''b'' som i bakåt och ''f'' som i framåt. Man kan också använda piltangenterna för att gå till vänster eller höger. Man kan förflytta sig ett ord bakåt eller framåt med M-b respektive M-f. Man kommer till början av raden med C-a och till slutet av den med C-e.
Readline har ett mycket användbart ''ångerkommando''. Trycker man C-_, så tas den senaste ändringen man gjort tillbaka. Genom upprepad användning av C-_ kan alla ändringar man gjort tas tillbaka, ända ned till den ursprungliga tomma raden. Kommandot C-x C-u, dvs C-x följt av C-u, är en synonym för C-_.
Ett annat användbart kommando är C-w, som raderar hela det ''ord'' som står bakom markören. Om ett kommando raderar flera tecken åt gången, så säger man att den raderade texten har klippts ut. Readline sparar alla urklipp. Därigenom kan det som klippts ut klistras in igen - när som helst, var som helst och hur många gånger som helst. Kommandot för att klistra in det senaste urklippet är C-y. Om man direkt efter C-y trycker M-y, så återfår man det näst senaste urklippet i stället för det senaste. Man kan upprepa detta och trycka M-y flera gånger för att få tillbaka äldre urklipp.
Men inte bara urklipp sparas, utan även de rader man skrivit in. Den förra kommandoraden man skrev in återfås med C-p eller genom att man trycker på piltangenten som pekar uppåt. Trycker man C-p igen, så återfår man den näst senaste kommandoraden osv. Man kommer till den äldsta bevarade kommandoraden genom att trycka M-<. Efter att ha gått några steg bakåt på detta sätt kan man gå tillbaka till den närmast yngre kommandoraden genom att trycka C-n eller piltangenten som pekar nedåt. För att återvävda till den yngsta kommandoraden, den som man höll på att redigera, kan man trycka M->.
Kommandot C-t kastar om de två bokstäver som står närmast markören. Detta är inte så vansinnigt som det kanske förefaller. Det händer nämligen ofta att man råkar skriva två bokstäver i fel ordning, särskilt om man är snabb vid tangentbordet. Så om man tex råkar skriva ''särskitl'' i stället för ''särskilt'' så kan man snabbt rätta felet genom att placera markören över bokstaven l och trycka C-t. Detta går mycket snabbare än att först radera ''tl'' och sedan skriva ''lt''. Kommandot M-t kastar istället om två ord.
Man kan söka bakåt bland de kommandorader man tidigare skrivit genom att trycka C-r och skriva in ett fragment av det kommando man söker. Om jag till exempel trycker först C-r och sedan h, så återfår jag kommandoraden date -help eftersom det är den senaste kommadoraden bland dem jag skrivit som innehåller texten ''h''. Trycker jag sedan e blir det ingen skillnad eftersom date -help innehåller texten ''he''. Men när jag därefter trycker j, så återfår jag istället kommadoraden echo hejsan svejsan eftersom den är den senaste som innehåller fragmentet ''hej''. Om jag då trycker på returtangenten, så utförs detta kommando. Sökningen avslutas också om jag trycker Esc, men kommandot utförs då inte genast, utan jag får möjlighet att redigera det först. Jag kan också trycka C-r igen för att återfå en äldre kommadorad som innehåller fragmentet ''hej''.
En annan viktig finess är att om man skriver de första tecknen i ett filnamn och sedan trycker på tabulatortangenten, så fyller Readline på med resten av filnamnet om det finns någon fil i den nuvarande katalogen vars namn börjar på det sättet. (Filer och kataloger diskuteras i de följande avsnitten.) Finns det flera filer vars namn börjar likadant, så tutar Readline till, och man får komplettera med ytterligare någon bokstav och därefter trycka på tabulatortangenten igen. Motsvarande gäller också för program- eller kommandonamn: om man skriver pass och sedan trycker på TAB, så kompletteras detta till passwd.
Om man ger Readline-kommandot M-nummer, dvs trycker ned metatangenten och samtidigt skriver talet nummer, så utförs nästa Readline-kommando nummer gånger. (Vissa Readline-kommandon tolkar dock nummer på ett annat sätt medan andra helt ignorerar det.) Kommandot M-8 följt av ett mellanslag skriver alltså ut åtta stycken mellanslag. Kommandot M-5 följt av C-_ tar tillbaka de fem senaste ändringarna. Kommandot M-1 2 följt av C-b flyttar markören tolv steg bakåt.
Readline konfigureras genom att man skriver in speciella kommandon i en fil med namnet .inputrc i sin hemkatalog. För att Readline ska behandla tecknen åäö korrekt, kan man behöva ha följande rader i den filen:
set convert-meta off set input-meta on set output-meta on
Readline har sina begränsningar; musen kan inte användas och bara en rad i taget kan redigeras. Dessa begränsningar hävs om man ger kommandona inifrån programmet Emacs.
UNIX lagrar information i filer. En fil kan till exempel innehålla en text, en bild eller ett datorprogram. Filerna i sin tur är inplacerade i kataloger. En katalog är alltså en förvaringsplats för filer. Varje fil och katalog har ett namn, som man använder då man refererar till dem.
Alla användare har en hemkatalog där de
egna filerna lagras.
Direkt efter inloggningen är hemkatalogen
nuvarande katalog, dvs man
''befinner sig'' i sin hemkatalog.
Kommandot ls ger en lista över filerna
i den nuvarande katalogen.$ ls
lenngren måltidssång
$Tydligen har jag två filer i min
hemkatalog. Den ena heter lenngren,
den andra måltidssång.
(Om ls inte skriver ut tecknen
åäö korrekt, så kan man ange flaggan
-N varje gång ls anropas.
Ett alternativ sätt är att ge kommandot
export LC_ALL=sv_SE.
I kapitel 6 ska vi förklara detta närmare.)
Man kan kopiera filer med kommandot cp. $ cp måltidssång bellman
$ ls
bellman lenngren måltidssång
$Ovan kopierade jag först filen måltidssång
och gav kopian namnet bellman. Därefter kontrollerade
jag att det gick väl genom att ge kommandot ls.
Utskriften visar att det verkligen finns en ny fil
med namnet bellman.
Om man anropar ls med flaggan -l,
så ges utförligare information om filerna.
Bland annat kan man utläsa hur stora filerna är
och när deras innehåll senast ändrades.$ ls -l
total 3
-rw-rw-r-- 1 göran göran 372 feb 1 16:48 bellman
-rw-rw-r-- 1 göran göran 649 feb 1 15:53 lenngren
-rw-rw-r-- 1 göran göran 372 feb 1 15:47 måltidssång
$Filerna bellman och måltidssång innehåller vardera 372
tecken, lenngren innehåller 649 tecken.
Det är klart att bellman och måltidssång är lika
stora eftersom bellman är en kopia av måltidssång.
Senast filen bellman ändrades var den 1 februari,
klockan 16.48.
Raden med texten total 3 anger hur mycket lagringsutrymme
filerna i katalogen förbrukar.
Vad de övriga delarna av utskriften ovan
betyder ska vi snart berätta.
Man kan byta namn på filer med kommandot mv.$ mv måltidssång epistel21
$ ls
bellman epistel21 lenngren
$Som synes har nu måltidssång bytt namn till
epistel21.
Kommandot för att radera en fil är rm.$ rm epistel21
$ ls
bellman lenngren
$Kontrollen med ls visar att filen epistel21
nu är borta.
Du är kanske van vid att få en varning om att filen kommer
att försvinna och ett krav på bekräftelse vid raderingskommandon?
Så är det inte här. UNIX
gör vanligtvis vad man säger utan att ställa några frågor,
även om konsekvenserna kan vara ödesdigra.
Observera också att det inte finns något sätt att få tillbaka
en fil som raderats!
Därför är det nödvändigt att man har
säkerhetskopior av alla viktiga filer.
En av systemadministratörens viktigaste arbetsuppgifter
är att regelbundet, lämpligen dagligen, göra
en säkerhetskopia av samtliga användares filer.
Om en användare av misstag råkar radera en fil, så kan
systemadministratören återställa filen till det skick den
var i föregående dag. Bara de ändringar som gjorts
det senaste dygnet går då förlorade. På detta sätt
minskas risken för katastrofer betydligt.
Det ska nämnas att om man anger flaggan -i till
rm, så ställs frågan om bekräftelse:$ rm -i bellman
rm: ta bort "bellman"? n
$ ls
bellman lenngren
$Om vi hade tryckt j i stället för n, så hade
bellman oåterkalleligen raderats. Man kan, om man så önskar,
ställa in det så att rm alltid frågar innan någon fil raderas.
Men då är risken stor att man efter ett tag
får som vana att
mekaniskt trycka j vid varje sådan fråga,
och då ger frågan inte längre något skydd.
För att skriva ut innehållet i en fil ordagrant kan man använda
cat.$ cat bellman
Så lunka vi så småningom
från Bacchi buller och tumult,
när döden ropar: Granne, kom,
ditt timglas är nu fullt.
Du gubbe, fäll din krycka ner,
och du, du yngling, lyd min lag:
den skönsta nymf, som åt dig ler,
inunder armen tag.
Tycker du, att graven är för djup,
nå välan, så tag dig då en sup,
tag dig se'n dito en, dito två, dito tre,
så dör du nöjdare.
$
Kommandot wc räknar antal rader, ord och tecken
i en given fil.$ wc bellman
12 71 372 bellman
$Utskriften från wc betyder att bellman
innehåller tolv rader, 71 ord och 372 tecken
(varje radslut räknas som ett tecken).
Om man vill studera en fil som innehåller för många rader för
att de ska få plats på skärmen samtidigt, så är cat inte ett
idealiskt kommando. Istället kan man använda more.$ more lenngren
Vår prost jag häromdagen såg
en morgon, då han ännu låg
matt utstäckt mellan tvenne lakan.
Hans kinder hade rosens färg,
hans runda armar hull och märg,
och magen, kullrig som ett berg,
sig hävde upp mot isterhakan.
Vid sängen stod ett bord, där denne andans man
sin frukost redan färdig fann
av smör och kycklingar, så läcker och så härlig.
Hans vördighet grep saken an
-More-(57%)När skärmen fyllts med text, stannar more upp
och skriver texten
-More-(57%)
nederst på skärmen.
För att få se mer av filen kan man då trycka på mellanslagstangenten.
(Kan du gissa varför kommandot more heter som det gör?)
Om man i stället trycker på b, så går more bakåt
i filen. Tryck på q för att avsluta, h för hjälp.
Man kan göra mycket mer med more, något vi återkommer till senare.
Många föredrar att använda kommandot less, som är en mer
avancerad version av more.
Kommandona head och tail skriver ut början respektive
slutet av en given fil. Så här får man se de sista tio raderna
i filen lenngren:$ tail lenngren
av smör och kycklingar, så läcker och så härlig.
Hans vördighet grep saken an
och fann likören rätt begärlig.
Sen han nu visat mycken nit
med klunk för klunk och bit för bit,
han åter sänkte sig på mjuka huvudgärden
och ropte: Store Gud, vad är vårt usla liv?
En ständig kamp mot synd och flärden.
O, Herre, mig Thin styrko giv
i thenna mödosamma världen!
$Om tio rader är för lite eller för mycket, så kan detta ändras
med hjälp av en flagga. De första fyra raderna av filen
bellman skrivs ut så här:$ head -4 bellman
Så lunka vi så småningom
från Bacchi buller och tumult,
när döden ropar: Granne, kom,
ditt timglas är nu fullt.
$
I UNIX tillåts vanligtvis inte att filnamn är längre än
256 tecken. Man brukar oftast använda filnamn som enbart består
av små bokstäver, men om man vill så kan man använda mycket
udda namn på sina filer.$ cp bellman 2+3
$ ls
2+3 bellman lenngren
$ rm 2+3
$UNIX skiljer på stora och små bokstäver; bellman
och Bellman betraktas som vitt skilda filnamn.
Varje fil har en ägare. Ägaren till en fil avgör vem som får göra vad med filen. Det finns tre slags rättigheter som är förknippade med varje fil: rätten att läsa den (ta del av dess innehåll), rätten att skriva till den (ändra dess innehåll) samt rätten att exekvera filen (att köra den som ett program). Som ägare till en fil kan man sätta upp det så att man själv har rätt att göra mer med filen än andra. I synnerhet brukar man se till att man själv får ändra i filen, men ingen annan. Om filen innehåller känslig information (som till exempel ens kärleksbrev), så brukar man se till att andra inte ens får läsa filen. Förutom att varje fil har en ägare, så är också varje fil associerad med en grupp. Vad grupper är till för behöver vi inte tänka på just nu, utan det beskrivs i stället i avsnitt 7.1.
Det är inte möjligt att specificera exakt för varje möjlig användare
vad de får och inte får göra med en viss fil.
Man kan inte säga att eva får göra si
och olle får göra så.
I stället bestämmer
man rättigheterna för tre kategorier av användare: för det första
filens ägare, för det andra de resterande medlemmarna i den grupp filen är
associerad med och för det tredje alla övriga.
För att ta reda på vilka rättigheter som gäller använder
man flaggan -l vid anrop av ls för att få
utförlig information.$ ls -l
total 2
-rw-rw-r-- 1 göran göran 372 feb 1 16:48 bellman
-rw-rw-r-- 1 göran göran 649 feb 1 15:53 lenngren
$Före den siffra (372 respektive 649) som talar om hur stor filen
är, står det vem som äger filen och vilken grupp filen
är associerad med. För filerna
ovan heter såväl ägaren som gruppen göran.
Betrakta nu den rad som beskriver filen bellman.
Att det första tecknet är - visar att det rör
sig om en vanlig fil (för kataloger
står det i stället d på motsvarande plats,
se nästa avsnitt).
De följande tre tecknen rw- avgör vad filens ägare
får göra med den.
Tecknet r anger att ägaren får läsa den;
tecknet w att ägaren får skriva över den
och tecknet -, eller snarare frånvaron av ett
x, att ägaren inte får exekvera den.
Därefter kommer tre tecken, rw-, som avgör
rättigheterna för
de resterande medlemmarna i gruppen göran
(i just detta fall finns dock inga andra gruppmedlemmar).
De sista tre tecknen, r--,
anger att övriga användare får läsa filen, men varken
ändra i den eller exekvera den.
Siffran efter skyddskoderna anger hur många
hårda länkar det finns till filen,
se avsnitt
.
Kommandot för att ändra skyddskoder heter chmod.
Om man vill att ägaren till filen fil ska ha skyddskoden
rw- ger man kommandot
chmod u=rw fil.
Om man vill att gruppen ska ha skyddskoden r--
blir kommandot chmod g=r fil.
Kommandot chmod o= fil ger ''övriga''
skyddskoden ---.
Man kan göra allt detta med ett enda kommando om man vill:$ chmod u=rw,g=r,o= bellman
$ ls -l bellman
-rw-r----- 1 göran göran 372 feb 1 16:48 bellman
$
Det finns också konstruktioner som
o+rx för att ''övrigas'' rättigheter ska
utökas med läs- och exekveringsrättighet,
och ug-r för att ta bort läsrättigheten för
ägaren och gruppen. I stället för ugo kan
man skriva a.$ chmod a-r bellman
$ ls -l bellman
--w------- 1 göran göran 372 feb 1 16:48 bellman
$ cat bellman
cat: bellman: Åtkomst nekas
$ chmod u+r bellman
$ ls -l bellman
-rw------- 1 göran göran 372 feb 1 16:48 bellman
$
Kataloger kan inte bara innehålla
filer, utan även andra kataloger
som då kallas underkataloger till den givna katalogen.
Så här tillverkar man en katalog med namnet dikter:$ mkdir dikter
$ ls
bellman dikter/ lenngren
$Att dikter är en katalog markeras i listan ovan med
ett snedstreck efter dess namn. (Vanligtvis krävs det
att man anropar ls med flaggan -F för
att kataloger ska markeras så här. En annan flagga,
--color, gör att filer och kataloger
markeras genom att deras namn skrivs med olika färger.)
Nu är alltså dikter
en underkatalog till min hemkatalog. Omvänt är min hemkatalog
föräldrakatalog till dikter.
Om man vill få en lista över
filerna i en annan katalog än
den nuvarande, så ska man helt enkelt ange den önskade katalogens
namn som argument till ls.$ ls dikter
$Än så länge är katalogen dikter tom. Men
vi ska nu kopiera filerna bellman och lenngren till
den. Kommandot cp kan användas på två sätt;
dels för att kopiera en fil till en annan, dels för att kopiera en
eller flera filer till en katalog.
I det senare fallet anger man destinationskatalogen som
sista argument.
(På motsvarande sätt kan man använda mv för att
flytta filer till en annan katalog.)$ cp bellman lenngren dikter
$ ls -l dikter
total 2
-rw------- 1 göran göran 372 feb 1 17:12 bellman
-rw-rw-r-- 1 göran göran 649 feb 1 17:12 lenngren
$Figur
ger ett diagram
över min hemkatalog och dess nuvarande innehåll.
Man kan radera tomma kataloger med rmdir.
Vill man radera en katalog inklusive dess innehåll, så
ska man använda rm med flaggan -r.$ mkdir sånger
$ ls
bellman dikter/ lenngren sånger/
$ rm sånger
rm: sånger: är en katalog
$ ls
bellman dikter/ lenngren sånger/
$ rmdir sånger
$ ls
bellman dikter/ lenngren
$ mkdir visor
$ cp bellman visor
$ ls visor
bellman
$ rmdir visor
rmdir: visor: Katalog inte tom
$ rm -r visor
$ ls
bellman dikter/ lenngren
$Ovan skapade jag först katalogen sånger.
Det gick inte att ta bort den med rm,
utan jag fick använda kommandot rmdir istället.
Därefter skapade jag katalogen visor och
kopierade bellman dit. Då gick det inte att ta
bort katalogen med rmdir eftersom den inte
var tom. Däremot kunde jag radera katalogen och dess innehåll
med rm -r.
För att förflytta sig till en annan katalog,
det vill säga byta nuvarande katalog,
använder man kommandot cd med namnet på
den katalog man vill komma till som argument.$ cd dikter
$ ls
bellman lenngren
$Nu befinner jag mig i underkatalogen dikter till
min hemkatalog. Men om jag vill komma tillbaka dit jag var nyss,
hur gör jag då? Ett sätt är att använda en mycket viktig finess,
nämligen att namnet .. (två punkter) betecknar föräldrakatalogen till
den katalog man befinner sig i.$ cd ..
$ ls
bellman dikter/ lenngren
$Nu slår oss tanken att den egna hemkatalogen
kanske är underkatalog till en annan!
Vi undersöker detta genast:$ cd ..
$ ls
eva/ göran/ lost+found/
$Ja, så var det. Vi provar samma
kommando igen:$ cd ..
$ ls
System.map@ dev/ home/ mnt/ tmp/
bin/ dosc/ initrd/ proc/ usr/
boot/ etc/ lib/ root/ var/
cdrom/ floppy/ lost+found/ sbin/ vmlinuz@
$Här fanns en massa kataloger. Men vi struntar i det tills vidare,
och fortsätter på den inslagna vägen.$ cd ..
$ ls
System.map@ dev/ home/ mnt/ tmp/
bin/ dosc/ initrd/ proc/ usr/
boot/ etc/ lib/ root/ var/
cdrom/ floppy/ lost+found/ sbin/ vmlinuz@
$Nej, det gick tydligen inte att komma längre. Vi befinner oss
i en katalog som inte är underkatalog till någon annan.
Nu har vi för övrigt gått vilse, och kan svårligen hitta tillbaka.
Lyckligtvis kan vi ta till hjälp att man
kommer hem till sin hemkatalog om man ger kommandot
cd utan att specificera någon destination.$ cd
$ ls
bellman dikter/ lenngren
$Men var någonstans är vi nu? Kommandot pwd
(''ange nuvarande katalog'') ger svaret:$ pwd
/home/göran
$Aha! Om jag i stället för cd gett först kommandot
cd home och sedan cd göran, så hade jag
också kommit hem. Den katalog jag var i nyss kallas för
rotkatalogen, och den har det koncisa namnet /.
Min hemkatalog heter
göran, detsamma som mitt användarnamn. Den är
en underkatalog till
home. Och home i sin tur
är underkatalog till rotkatalogen.
På detta sätt är alla kataloger ordnade i en hierarki
med rotkatalogen överst (eller underst, beroende på hur
man ser det) i hierarkin. Det är grundläggande för UNIX att det endast finns en sådan hierarki,
filsystemet är gjutet i ett stycke
(eller åtminstone ser det ut så).
Ett alternativt sätt att referera till katalogen dikter är att ange dess absoluta läge i filsystemet, /home/göran/dikter. Man säger att detta är sökvägen till katalogen. Poängen med att ange sökvägen är att man därigenom kan referera till filer eller kataloger som inte finns i just den nuvarande katalogen. Filer har också sökvägar. Sökvägen till filen bellman i min hemkatalog är /home/göran/bellman, medan sökvägen till filen bellman i underkatalogen dikter är /home/göran/dikter/bellman. Trots att dessa filer har samma namn, kan man med hjälp av sökvägar ange vilken av dem man åsyftar.
Så här kan man se vad som finns i katalogen /home/eva:$ ls /home/eva
LPAuppsats/ index.html paper.dvi paper.tex~
ekerö.jpg index.html~ paper.log post/
idéhistoria/ paper.aux paper.tex övrigt/
$Alternativt kunde jag ha gett kommandot ls ../eva.
Detta fungerar om jag befinner mig i min hemkatalog
/home/göran, för då står .. för
/home. Man säger att ''../eva'' är en relativ
referens till katalogen, i motsats till ''/home/eva''
som är en absolut referens.
I detta sammanhang är det kanske lämpligt att påpeka att namnet . (en punkt) betecknar den nuvarande katalogen. Så vi kan använda kommandot cp /bin/bash . om vi skulle vilja kopiera filen bash från katalogen /bin till den nuvarande katalogen.
För att ta reda på hur mycket utrymme en viss katalog
(inklusive dess underkataloger) förbrukar,
ska man använda kommandot du.
Som argument anger man vilken katalog som avses.
Om man inte anger flaggan -s, så skrivs också
information om underkatalogerna ut.$ du
3 ./dikter
16 .
$ du -s /home/eva
162101 /home/eva
$Siffrorna i utskriften står för antalet kilobyte.
Min hemkatalog, inklusive alla underkataloger,
använder alltså 16 kilobyte lagringsutrymme.
Jag ska kanske nämna vilka enheter man använder
för att beskriva datorminne?
En gigabyte är 1024 megabyte.
En megabyte är 1024 kilobyte.
En kilobyte är 1024 byte.
En byte är ett lagringsutrymme i vilket
man kan lagra ett tecken som tex en bokstav
eller en siffra. (Eller snarare, i en byte lagras ett
tal mellan 0 och 255, och detta tal tolkas ofta
som ett tecken med hjälp av tabellen på
sida
.)
En sida text består av cirka 2000 tecken,
ungefär 2 kilobyte. En megabyte motsvarar
ungefär 500 sidor text.
I UNIX finns en mer eller mindre standardiserad struktur för hierarkin av kataloger. Till exempel innehåller /bin vissa av de viktigaste programmen (som bash, cp och ls), /sbin innehåller systemprogram, huvuddelen av /usr innehåller användarprogram och filer som de behöver, /home innehåller hemkataloger för de olika användarna, i /etc finns viktiga konfigurationsfiler osv.
Det är en konvention att filer vars namn inleds med en punkt
ska döljas, inte för att de är hemliga utan för att man kanske
sällan ändrar i dem och vill ha dem ur vägen.
Kommandot ls respekterar denna konvention. Om man vill
se samtliga filer i den nuvarande katalogen, så ska man anropa
ls med flaggan -a.$ ls -a
./ .bash_profile bellman
../ .bashrc dikter/
.bash_history .inputrc lenngren
$Jag har alltså fyra ''dolda'' filer i min hemkatalog.
Katalogerna . och .. återges som synes
också när ls anropas med flaggan -a.
Nedan vill vi ha utförlig information om samtliga filer och anropar
därför ls med både -l och -a. (I likhet med
många andra kommandon tillåter ls att man förkortar
exempelvis -l -a till -la.)$ ls -la
total 16
drwxrwxr-x 3 göran göran 1024 feb 1 17:24 ./
drwxrwsr-x 9 root staff 1024 nov 23 22:09 ../
-rw-rw-r-- 1 göran göran 6711 feb 1 17:23 .bash_history
-rw-rw-r-- 1 göran göran 235 feb 1 17:23 .bash_profile
-rw-rw-r-- 1 göran göran 81 feb 1 17:23 .bashrc
-rw-rw-r-- 1 göran göran 239 feb 1 17:24 .inputrc
-rw------- 1 göran göran 372 feb 1 16:48 bellman
drwxrwxr-x 2 göran göran 1024 feb 1 17:12 dikter/
-rw-rw-r-- 1 göran göran 649 feb 1 15:53 lenngren
$Samtliga filer och kataloger ägs av göran och är
associerade med gruppen göran, med undantag av
katalogen .. som ägs av root och hör till
gruppen staff.
Motsvarande skyddskoder som för filer
används också för kataloger, men tolkningen är
något annorlunda.
Ett r betyder att man får se namnen
på de filer som katalogen
innehåller (tex med ls).
Ett x betyder att man får gå
in i katalogen (tex med cd).
Om x inte är påslaget, så kan man överhuvudtaget
inte göra något med katalogen (förutom att se vad den
innehåller om r är påslaget).
Ett w betyder att man får skriva till katalogen
(dvs skapa nya filer eller radera filer i katalogen).
Övning. Logga in och ändra ditt lösenord.
Övning. Slå upp din födelsemånad med hjälp av kommandot gcal (eller cal, ifall gcal inte finns tillgängligt).
Övning. Läs bruksanvisningen för echo med hjälp av man.
Övning. Skriv en kommandorad med några ord. Hoppa omkring i raden med C-a, C-e, M-a och M-e. Prova C-w och C-y. Tryck C-_ några gånger.
Övning. Ge i tur och ordning kommandona less /etc/passwd, date och cal 10 1997. Använd sökfunktionen C-r och tryck först l, sedan e för att återfå det första komandot. (Tryck Esc eller vänsterpil för att avsluta.)
Övning. Prova några andra av redigeringskommandona i tabell 1.1
Övning. Har du någon .inputrc, och hur ser den i så fall ut? Om inte, skapa en så att du kan använda å, ä och ö.
Övning. Ge något kommando som är mer än en rad långt. Hur ser den sekundära prompten ut?
Övning. Undersök vilka filer som finns i katalogen /bin.
Övning. Gå till katalogen /etc och kontrollera vilka filer som finns där. Hur många rader, ord och tecken har filen passwd? Skriv ut de tolv sista raderna av filen passwd. Skriv ut hela filen med cat. Läs filen en skärm i taget med more eller less. Gå därefter tillbaka till din hemkatalog.
Övning. Undersök vilka filer som finns i din hemkatalog. Finns det dolda filer där? Titta på någon av dem i så fall.
Övning.
Skapa en katalog med namn test.
Se till att du har rättigheterna rwx för katalogen.
Kopiera filen passwd
från /etc till test och
ta bort din egen rättighet att skriva över filen.
Vad händer om du då försöker radera filen?
Övning. Skapa en katalog med namn test och kopiera filen passwd från /etc till test. Ändra sedan rättigheterna så att du själv får exekvera, men varken skriva till eller läsa katalogen. Vad händer om du ger kommandot ls test? Gå in i test med kommandot cd test och prova i tur och ordning ls, cat pass och cat passwd. Förklara vad som händer.
Ett av de främsta och viktigaste programmen i UNIX-miljön är Emacs. Ytligt sett är Emacs en textredigerare, men tack vare dess närmast ändlösa flexibilitet kan Emacs tjäna som ett universalprogram - via Emacs kan man typsätta sina dokument, programmera, hantera sina filer, skicka datorpost och läsa webbsidor, bland mycket annat. Emacs har ett skräddarsytt läge för varje tillämpning. När man skriver ett C-program ställer Emacs in sig i C-läget; när man arbetar med typsättningsprogrammet LATEX inifrån Emacs befinner sig Emacs i sitt LATEX-läge osv.
Emacs är uppbyggt kring en kärna som ger den grundläggande funktionaliteten och som dessutom implementerar ett helt programmeringsspråk, Emacs lisp. Till denna kärna kommer ett stort antal moduler, skrivna i Emacs lisp, som utökar funktionaliteten och definierar olika lägen. Till exempel finns en modul som möjliggör stavningskontroll av texter och en grupp av moduler som tillsammans definierar LATEX-läget.
Om man inte är nöjd med hur Emacs fungerar, så kan man ofta anpassa det efter sin egen smak genom att ändra på vissa inställningar, antingen inifrån Emacs eller genom att lägga in kommandon i en fil med namnet .emacs i sin hemkatalog. För att tecknen åäö ska behandlas korrekt kan det vara nödvändigt att lägga följande kommandon i filen .emacs:
(standard-display-european t)
(set-input-mode (car (current-input-mode))
(nth 1 (current-input-mode))
0)
Emacs startas med kommandot emacs, eventuellt tillsammans
med namnet på en eller flera filer som man vill arbeta med.
Exempelvis kan man för att redigera filen bellman ge
kommandot$ emacs bellmanProgrammet avslutas
med C-x C-c, dvs först kommandot C-x och
därefter C-c. Det snabbaste sättet att ge detta kommando
är att hålla kontrolltangenten nedtryckt med lillfingret
och samtidigt trycka först x med långfingret och sedan
c med pekfingret på vänster hand.
(Emacs är, liksom UNIX i övrigt, kärvt för nybörjare,
med många kryptiska kommandon som kan tyckas omöjliga att memorera.
Men när man vant sig vid programmet upptäcker man att tangenterna
tycks ''sitta rätt'', så att man kan arbeta snabbt och effektivt.)
För den som inte tidigare använt Emacs rekommenderar jag varmt den inbyggda introduktionen, som startas med kommandot C-h t. Genom den får man lära sig hantera de grundläggande funktionerna för textredigering.
Ett annat kommando som är bra att känna till är C-g. Det avbryter ett eventuellt påbörjat kommando. Om man av misstag råkar ge ett kommando och det börjar hända märkliga saker, så kan ordningen alltså ofta återställas med C-g. Om däremot ett kommando redan har utförts och förändrat den text man arbetar med, så ska man använda ångerkommandot C-_ för att återställa bufferten till det skick den var i före kommandot. Genom att upprepade gånger ge kommandot C-_ kan man omintetgöra förändringar som gjorts långt tidigare. En synonym för C-_ är C-x u.
Tabell 2.1 ger en förteckning av de kommandon som beskrivs i detta avsnitt.
|
När man öppnar en fil i Emacs, vare sig genom att ange dess namn i kommandot som startar Emacs eller med kommandot C-x C-f, skapas en buffert i emacs. Bufferten innehåller en kopia av filens innehåll. Man arbetar alltså inte direkt mot filen så som den är sparad på tex hårddisken, utan endast med en kopia. För att de ändringar man gjort i en buffert ska bli beständiga måste man spara bufferten. Kommandot för att spara en buffert, och skriva över den motsvarande filen, är C-x C-s. Emacs kan hantera ett stort antal buffertar åt gången. Man kan alltså arbeta med flera olika filer samtidigt.
När Emacs startats ser man menyraden överst i Emacs-skärmen. Med hjälp av menyraden kan man välja vissa kommandon i stället för att skriva in dem via tangenterna. Under menyn finns en stor yta, ett fönster,2.1där man arbetar med sina texter. Långt ned på Emacs-skärmen finns en markerad rad, lägesraden.
Den kan se ut ungefär så här:
--**-Emacs: epistlar.tex (LaTeX)--L110--34%-------Låt oss säga något om vilken information man kan utläsa ur lägesraden: Emacs identifierar sig med texten
Emacs:, och anger att man arbetar med filen epistlar.tex.
De båda asteriskerna till vänster betyder att man inte sparat de senaste ändringarna av sin fil.
När bufferten är sparad står det -- i stället för **. (Och om den fil man har framme skulle vara
skrivskyddad, så står det %%.) Naturligtvis kan man också se vilket läge Emacs befinner sig i -
LATEX-läget.
Dessutom ser vi att vi befinner oss vid rad 110 och att
34% av bufferten epistlar.tex ligger före texten som
för tillfället visas i fönstret.
Om man kan se början av bufferten, så står det Top snarare än 0%;
om man kan se slutet av bufferten, så står det Bot - men om bufferten är så kort att man kan
se den i sin helhet, så står det i stället All.
Det lilla område som finns under lägesraden kallas för minibufferten. Den används då man i samband med något kommando behöver mata in text som inte hör till det dokument man arbetar med. Till exempel betyder kommandot C-x C-f att man vill öppna en fil för redigering. När man gett detta kommando flyttas markören ned till minibufferten, och Emacs frågar efter namnet på den fil man vill öppna. Ett annat exempel är namngivna kommandon som goto-line, eller M-x goto-line som vi ofta kommer att skriva. För att kunna ge sådana kommandon trycker man först M-x, varefter markören flyttas till minibufferten, så att man där kan skriva kommandot. (Efter att man gett kommandot goto-line får man en följdfråga i minibufferten, nämligen om vilken rad man vill gå till.)
Ett koncept som genomsyrar all användning av Emacs är punkten.2.2Med ''punkten'' menas den position i bufferten där man för tillfället befinner sig. Den text man skriver in hamnar vid punkten. Emacs använder markören för att visa var punkten finns. Närmare bestämt: Punkten befinner sig alltid mellan två tecken i bufferten. Markören placeras över det tecken i bufferten som kommer direkt efter punkten, dvs till höger om den. Till exempel, om punkten befinner sig mellan bokstäverna x och m i ''exmpel'', så placerar Emacs ut markören över bokstaven m. Om man då trycker på e så läggs ett e in mellan x och m, vilket ger ''exempel''. Därefter befinner sig punkten mellan e och m, och markören står fortfarande över m.
Som komplement finns också begreppet märket, en position i texten som man markerat med C-mellanslag för att tex senare kunna återvända dit snabbt eller för att kunna klippa ut texten mellan märket och punkten. Texten mellan märket och punkten kallas för regionen. När märket är satt lyser Emacs upp regionen. Om detta är tröttsamt eller störande, så kan man slippa det genom att trycka C-g.
Det lättaste sättet att vandra omkring i sin fil, dvs
att flytta punkten, är att använda piltangenterna
samt Page Up och Page Down.
Ofta vill man också flytta sig till början av en rad
med kommandot C-a, eller till slutet av den med
C-e. Men det finns naturligtvis
åtskilliga andra kommandon som påverkar
punkten och märket - se tabell
.
| |||||||||||||||||||||||||||||||||||||||
För inskrivning av text behövs inga kommandon, man matar bara in texten precis som vanligt. Tecknet bakom punkten (dvs närmast bakom markören) raderas med Delete eller raderingstangenten; håller man samtidigt metatangenten nedtryckt, så klipps hela det ord som står före punkten ut. (Med att klippa ut menar jag att med ett kommando radera vad som kan vara ett större stycke text.) Varje gång något klipps ut sparas det i en särskild buffert, urklippsringen. Det senast urklippet återfås (det klistras in) på kommandot C-y.
Man flyttar ett stycke text genom att klippa ut den, flytta punkten dit man vill ha texten, och sedan klistra in den.
Om man genast efter C-y ger kommandot M-y, så byts den nyss inklistrade texten mot det näst senate urklippet; genom att upprepade gånger trycka M-y återfår man successivt äldre och äldre urklipp. Om man kommit till det äldsta urklippet och åter trycker M-y, så startar processen om med det senaste urklippet - det är därför man talar om en ring av urklipp.
|
Synnerligen ofta händer det att man arbetar med en lång text, och vill leta upp ett visst ord i texten. I sådana situationer ska man använda Emacs sökfunktion. Den enklaste formen av sökning är C-s (för att söka framåt i bufferten) eller C-r (för att söka bakåt i bufferten). Efter att ha gett kommandot C-s får man i minibufferten skriva in den text man Emacs ska söka efter i bufferten. Sökningen sker efter hand som man skriver in söktexten. Om man trycker på returtangenten, så avslutas sökningen. Om emacs finner en förekomst av söktexten och man vill komma till nästa, så ska man trycka C-s (eller C-r) igen. När sökningen avslutats är märket placerat där sökningen började, så man kan komma tillbaka med kommandot C-x C-x.
Med kommandot M-% kan man byta ut alla
eller vissa förekomster av en text mot en annan,
se tabell
.
| ||||||||||||||||||||||||||||||||||||||||
Den första gången man under en Emacs-session sparar en förändrad version av en fil, gör Emacs en säkerhetskopia av filen för den händelse att man vid ett senare tillfälle skulle ångra de ändringar man gjort. Om vi till exempel gör ändringar i filen bellman och sparar filen, så kopieras filen i sitt ursprungliga skick till namnet bellman~. Den nya versionen lagras därefter under namnet bellman. Säkerhetskopian har alltså samma namn som filen bortsett från att ett tilde har lagt till på slutet.
Det finns vissa riskmoment i att ändringar man gjort inte sparas genast utan först då man ger kommandot för att spara: om man glömmer bort att spara tillbaka bufferten, så förlorar man sina ändringar. Visserligen är detta ibland precis vad man vill, nämligen om man kommer på att ändringarna var misslyckade och man föredrar den ursprungliga versionen av filen. Men oftast vill man behålla de tillägg man gjort i en fil, så om man är på väg att lämna Emacs trots att det finns osparade buffertar, så frågar Emacs både en och två gånger om bekräftelse av att detta verkligen är ens avsikt. Det finns för övrigt ett kommando för att kasta bort de ändringar man gjort och återställa bufferten så som den är sparad på sekundärminnet, M-x revert-buffer. Även vid detta kommando frågar Emacs ifall detta verkligen är vad man vill.
Vidare, om det blir strömavbrott, så raderas innehållet i datorn och man får inte tillfälle att spara sina ändringar som kanske tagit flera timmar att skriva in. För att ge ett visst skydd mot sådana olyckor gör Emacs med jämna mellanrum tillfälliga kopior av de filer man ändrat. Därigenom kan man efter ett strömavbrott eller en systemkrasch återfå alla eller de flesta av de tillägg man gjort till filen. Dessa autosparade buffertar får samma namn som den fil man arbetar med, bortsett från att tecknet # lagts till i början och på slutet. Om bellman autosparas, så sker det alltså under namnet #bellman#.
Om man någon gång öppnar en fil av vilken det finns en nyare, autosparad version, så påpekar Emacs detta, och uppmanar en att ge kommandot M-x recover-file för att övergå till den nyare versionen i stället.
Ibland vill man kunna se mer är en fil åt gången då man arbetar med Emacs. För att kunna göra det ska man dela upp Emacs-skärmen horisontalt och/eller vertikalt med kommandona C-x 2 eller C-x 3. Varje fält som då uppstår kallas för ett fönster i Emacs.
Man justerar fönsterstorleken med kommandona C-x ^ (gör fönstret högre), C-x } (gör fönstret bredare) samt C-x { (gör fönstret smalare).
Kommandot C-x o flyttar markören till ett annat fönster. Om Emacs-skärmen är indelad i flera fönster, så kan man ta bort alla fönster utom det som markören befinner sig i med kommandot C-x 1.
Man kan skicka och ta emot datorpost från Emacs. Den enklaste modulen för detta är RMAIL. Den startas med kommandot M-x rmail. Innan man startar modulen bör man dock konfigurera den. För att ange sitt namn och sin datorpostadress ska man lägga in raderna
(setq user-full-name "Göran Andersson") (setq user-mail-address "goran_a@sslug.dk")i filen .emacs (men byt först till ditt namn och din adress). För att post ska kunna skickas iväg kan raderna
(setq smtpmail-default-smtp-server "mail.teledyrt.com") (setq smtpmail-local-domain nil) (setq send-mail-function 'smtpmail-send-it) (load-library "smtpmail")behöva läggas in i .emacs. I stället för mail.teledyrt.com ska det stå vilken datorpostserver man använder.
Om man ska hämta hem post från någon annan dator med hjälp av RMAIL måste följande rader skrivas in i .emacs:
(setenv "MAILHOST" "lukas.teledyrt.com")
(setq rmail-primary-inbox-list '("po:goran97") rmail-pop-password-required t)
(setq-default rmail-pop-password "tax45lax")
(load-library "message")
I sället för lukas.teledyrt.com ska det stå adressen
till den dator du hämtar posten från. Byt också ut
goran97 mot ditt användarnamn på den datorn
och tax45lax mot ditt lösenord där.
Raden som anger lösenordet bör utelämnas om du
inte är enda användaren på datorn, annars är risken stor
att någon kan komma åt det - även om du ser till att
lässkydda filen .emacs. Om man inte
vill skriva in sitt lösenord i .emacs, så
frågar Emacs efter lösenordet varje gång man hämtar hem post.
En annan och mer avancerad modul för datorpost är VM. Den startas med kommandot M-x vm. Konfigurationen är densamma som ovan, men om man ska hämta post från någon annan dator ska man också lägga in raderna
(setq vm-spool-files
(list
(list "~/INBOX"
"lukas.teledyrt.com:110:pass:goran97:tax45lax"
"~/INBOX.CRASH")))
i sin .emacs.
Man kan sätta tecknet * i stället för lösenordet om
man inte vill skriva in det i en fil så här.
För att kontrollera stavningen i en buffert ska man ge kommandot M-x ispell-buffer. För att detta ska fungera måste programmet ispell vara installerat på datorn. En svensk ordlista till ispell finns att hämta på adressen http://www.sslug.dk/ispell/. Det kan vara praktiskt att lägga in raden
(setq ispell-dictionary "svenska")i sin .emacs, för annars kan man behöva ge kommandot M-x ispell-change-dictionary för att byta till den svenska ordlistan.
Övning. Starta Emacs och avsluta därefter direkt.
Övning. Starta Emacs och ge kommandot C-h t. Arbeta en stund med uppgifterna i den fil som då dyker upp!
Övning. Skapa med hjälp av Emacs en fil med följande innehåll:
Solen glimmar blank och trind, vattnet lik en spegel; småningom uppblåser vind i de fallna segel; vimpeln sträcks, och med en år Olle på en höbåt står; Kerstin ur kajutan går, skjuter lås och regel.Ge filen namnet ulla.
Näst efter Emacs brukar skalet, eller kommandotolken som det också kallas, vara det program som används mest. Det är skalet som läser in och tolkar de kommandon man ger och som ser till att de exekveras. Man kan tänka på skalet som en betjänt som tar emot en order och som vidarebefordrar den så att den blir utförd. Vägen till de program som finns på datorn går nästan alltid via skalet. Det är därför viktigt att man kommer väl överens med skalet, och att man är förtrogen med dess ''språk''. Vi ska i detta kapitel beskriva några av de finesser skalet erbjuder. Förmodligen är det enklast att till en början bara bläddra igenom detta kapitel, och återvända hit för att studera detaljerna först när de verkligen behövs.
I UNIX finns flera olika skal, varav de mest använda är Bourne-skalet, C-skalet, Korn-skalet och Z-skalet. I mångt och mycket är dessa skal lika, men de skiljer sig åt på vissa detaljer. För enkelhets skull ska vi i denna bok hålla oss till ett enda skal, en modern och oerhört kraftfull variant av Bourne-skalet som heter Bash - Bourne-again shell.3.1
Antag att en viss katalog innehåller följande filer:$ ls
epistel23.text epistel28.text~ fredman.html~ haga.sång~
epistel25.text epistel36.text fredman.ps movitz.html
epistel28.text fredman.html haga.sång winblad.html
$Om vi nu vill radera alla filer vars namn slutar med ett
tildetecken
så kan vi ge kommandot rm epistel28.text~ fredman.html~ haga.sång~.
Men det känns lite omständligt att behöva räkna upp alla dessa filer.
Lyckligtvis finns det ett enklare sätt.
Man kan nämligen referera till flera filer
samtidigt med hjälp av jokertecken.
Jokertecknen är *, ? och [. Om ett argument innehåller något av dessa tecken, så tolkar skalet argumentet som ett mönster som ska paras ihop med namnen på filerna (och katalogerna) i den nuvarande katalogen. Om ett eller flera av filnamnen ''matchar'' mönstret så skriver skalet om kommandot man gav genom att byta ut mönstret mot en alfabetiskt sorterad lista av de filnamn som matchar mönstret. Om mönstret däremot inte matchas av något filnamn, så görs inga omskrivningar, utan skalet lämnar då mönstret som det är.
Jokertecknet * matchar
vilken som helst följd av noll eller flera tecken.
Mönstret *~ matchar därför precis de filnamn som slutar
med ett tilde.
För att radera alla filer vars namn slutar med tilde kan vi
tydligen ge kommandot rm *~. Detta kommando skriver skalet
(utan att det syns) om till rm epistel28.text~ fredman.html~ haga.sång~
innan det exekveras. Tolkningen görs alltså av skalet -
kommandon som tex rm vet ingenting om jokertecken.$ rm *~
$ ls
epistel23.text epistel36.text haga.sång
epistel25.text fredman.html movitz.html
epistel28.text fredman.ps winblad.html
$
I de följande exemplen, där vi inte gör något meningsfullt utan bara demonstrerar hur jokertecken fungerar, ska vi använda kommandot echo som ju skriver ut sina argument exakt som de är. Då får vi se hur argumenten såg ut efter omskrivningen.
Mönstret epistel* matchar alla de filer vars namn börjar med
''epistel'':$ echo epistel*
epistel23.text epistel25.text epistel28.text epistel36.text
$Så här väljer man ut alla filer vars namn slutar med .html:$ echo *.html
fredman.html movitz.html winblad.html
$Det finns ingen fil vars namn slutar med .htm:$ echo *.htm
*.htm
$Här ser vi att skalet skickar mönstret vidare oförändrat
ifall det inte matchar något filnamn.
Det får förekomma jokertecken i fler än ett av argumenten:$ echo winblad.* fredman.*
winblad.html fredman.html fredman.ps
$Man får också använda flera jokertecken i samma mönster:$ echo e*3*t
epistel23.text epistel36.text
$ echo *n*
fredman.html fredman.ps haga.sång winblad.html
$På detta sätt fann vi alla filnamn som innehåller bokstaven n.
Jokertecknet ? matchar ett (exakt ett) godtyckligt tecken.$ echo epistel2?.text
epistel23.text epistel25.text epistel28.text
$ echo *.??
fredman.ps
$Mönstret *.?? matchar de filer vars namn slutar
på en punkt följt av exakt två tecken.
Det finns två undantag mot reglerna för jokertecken.
Det ena undantaget är att
tecknet / måste anges uttryckligen i mönstret.
Så till exempel matchar mönstret
/etc/*wd filnamnet /etc/passwd
men inte filnamnet /et*wd.$ echo /et*wd
/et*wd
$ echo /etc/*wd
/etc/passwd
$ echo /usr/*/emacs
/usr/bin/emacs /usr/doc/emacs /usr/lib/emacs
$Det andra undantaget är att filnamn som inleds med en punkt
endast matchas av mönster som också inleds med en punkt.$ echo .*
. .. .bash_history .bash_profile .bashrc .inputrc
$ echo .ba*
.bash_history .bash_profile .bashrc
$
Om man vill att mönstret ska matcha bara vissa utvalda tecken,
så behövs andra hjälpmedel än * och ?,
nämligen [...].
Mellan hakparenteserna ska man räkna upp ett antal tecken,
och då tolkar skalet detta som ett mönster som matchar
ett (exakt ett) av de uppräknade tecknen.
Till exempel matchar [058] ett valfritt av tecknen 0, 5 och 8:$ echo epistel2[058].text
epistel25.text epistel28.text
$Man kan också ange intervall, [3-7] matchar 3, 4, 5, 6
eller 7, och [a-d] matchar a, b, c eller d.$ echo epistel2[3-7].text
epistel23.text epistel25.text
$ echo *.[a-r]*
fredman.html fredman.ps movitz.html winblad.html
$Om man vill att mönstret ska matcha alla tecken som inte
är uppräknade, så ska man ange tecknet ^ direkt
efter [. Mönstret [^te-h] matchar alltså exakt ett tecken
som inte är något av t,e,f,g eller h.$ echo *[^te-h]
fredman.html fredman.ps movitz.html winblad.html
$(Man kan använda ! som en synonym för ^.)
Låt oss avslutningsvis nämna en liten komplikation: Hur kan man ange ett mönster som
ska matcha exakt ett av tecknen 2, - och 5?
Inte som 2-5, för då tolkas det som 2,3,4 eller 5. Men om man sätter
tecknet - först eller sist, som i [-25], så förstår skalet
att man inte syftar på ett intervall. På motsvarande sätt
gäller att om man vill räkna upp ett antal
tecken varav ett är ], så ska man ange detta först.
Exempelvis matchar []aö] ett av tecknen
], a och ö.
Med hjälp av skalet kan man få flera kommandon utförda samtidigt. Man kan också avbryta kommandon, eller tillfälligt stoppa dem för att låta dem fortsätta vid ett senare tillfälle. I det här avsnittet ska vi berätta hur det går till.
Antag att vi kör ett kommando
som tar lång tid och blir otåliga
medan vi sitter och väntar på att prompten ska
återvända. När vi tröttnat på att vänta kan vi
trycka C-c. Då gripet skalet in och avbryter kommandot,
och prompten återvänder omedelbart.$ cp /usr/bin/emacs .
$ ls -l emacs
-rwxrwxr-x 1 göran göran 1814268 feb 5 14:19 emacs*
$ gzip -9 emacs Efter en stund trycker jag C-c...
$ ls -l emacs
-rwxrwxr-x 1 göran göran 1814268 feb 5 14:19 emacs*
$Vad var det som hände ovan? Jo, först kopierade jag en stor
fil, den som innehåller programmet Emacs, till den nuvarande katalogen.
Sedan startade jag ett kommando, gzip emacs, som komprimerar filen.
Efter ett antal sekunder hade prompten fortfarande inte
återvänt, och då tryckte jag C-c.
Därigenom avbröt jag kommandot, och filen emacs
blev inte komprimerad. (Asterisken som ls skriver ut efter filnamnet
emacs markerar att filen är exekverbar.)
Metoden att avbrya ett kommando med C-c är destruktiv;
den del av arbetet som kommandot redan gjort är förgäves.
Ett annat och bättre sätt att slippa vänta på prompten
medan ett kommando är igång, är att låta kommandot
köra i bakgrunden. Detta innebär att kommandot
undviker att blockera det skal man arbetar vid.
Medan körningen av kommandot pågår kan man då ge
nya kommandon.
För att ett kommando ska köra i bakgrunden,
ska man helt enkelt skriva tecknet & efter kommandot.$ gzip emacs &
[1] 2792
$ ls
bellman dikter/ emacs* emacs.gz lenngren
$ date
tor feb 5 14:37:28 CET 1998
$ ls -l
total 625
-rw------- 1 göran göran 372 feb 1 16:48 bellman
drwxrwxr-x 2 göran göran 1024 feb 1 17:12 dikter/
-rwxrwxr-x 1 göran göran 632176 feb 5 14:19 emacs.gz*
-rw-rw-r-- 1 göran göran 649 feb 1 15:53 lenngren
[1]+ Done gzip emacs
$Eftersom jag satte tecknet
& efter kommandot gzip emacs, kördes det i bakgrunden.
Därför återkom prompten genast efter att ett
meddelande, [1] 7809, skrivits ut. Därigenom kunde jag
ge andra kommandon, som ls och date, medan
gzip arbetade med att komprimera filen emacs.
Siffran 7809 är ett slags namn,
processidentifikationsnumret, som systemet gav kommandot
som bestod i att köra gzip på emacs.
Numret 1 som skrevs ut är ett namn,
jobbnumret, som skalet gav kommandot.
Vilken nytta man kan ha av processidentifikationsnumret
ska vi berätta i avsnitt 5.5.
I det här avsnittet intresserar vi oss bara för jobbnumret.
När jobb nummer 1 var klart meddelades detta
med utskriften [1]+ Done.
(Eller snarare, när ett jobb är klart väntar skalet med att
tala om detta tills det nästa gång får tillfälle att skriva ut en
prompt. Därigenom slipper man bli störd medan man skriver
något.) Man kan se ovan att filen komprimerades till lite drygt
en tredjedel av sin ursprungliga storlek. Den komprimerade
filen har samma namn som den ursprungliga men med tillägget .gz.
Kommandon som inte kör i bakgrunden sägs köra
i förgrunden. Om ett kommando som kör i förgrunden visar
sig ta alltför lång tid, behöver man inte nödvändigtvis avbryta det med
C-c. I stället kan man trycka C-z.
Då stoppas körningen, men bara tillfälligt.
Den kan fortsätta från samma punkt vid ett senare tillfälle
då vi har tid att vänta.
En körning som har avbrutits med C-c
kan däremot inte återupptas.
I exemplet nedan börjar jag dekomprimera filen
emacs.gz i förgrunden med kommandot gunzip,
men stoppar kommandot efter en stund:$ gunzip emacs.gz Efter en stund trycker jag C-z
[1]+ Stopped gunzip emacs.gz
$ ls
bellman dikter/ emacs emacs.gz* lenngren
$Kommandot är nu stoppat. Det har fått jobbnummer 1,
men det sitter bara och väntar på nya signaler.
Vi kan aktivera kommandot igen, och sätta det i
förgrunden, med kommandot
fg %1. Procenttecknet följt av ett nummer är en
referens till jobbet med detta nummer.$ fg %1
gunzip emacs.gz
$ ls
bellman dikter/ emacs* lenngren
$En liten stund efter kommandot fg %1 återvände promtpen,
och då var filen komprimerad.
Vi gör nu ett nytt experiment:$ gzip -9 emacs Efter en stund trycker jag C-z
[1]+ Stopped gzip -9 emacs
$Flaggan -9 gör att gzip
försöker komprimera bättre, men oftast blir enda skillnaden
att det tar längre tid. Efter en stund stoppade jag
kommandot med C-z.
För att få reda på vilka jobb som är igång, inklusive de som är
stoppade, ska man ge kommandot jobs.$ jobs
[1]+ Stopped gzip -9 emacs
$Man kan aktivera ett stoppat jobb, och låta det fortsätta i
bakgrunden, med kommandot bg.$ bg %1
[1]+ gzip -9 emacs &
$ ls
bellman dikter/ emacs* emacs.gz lenngren Jag väntar en stund...
$ ls
bellman dikter/ emacs.gz* lenngren
[1]+ Done gzip -9 emacs
$ rm emacs.gz
$Jag lät det stoppade
jobbet köra vidare i bakgrunden genom att
ge kommandot bg %1. Medan jobbet var igång
kunde jag använda skalet; i körningen ovan gav jag kommandot
ls samtidigt som
komprimeringskommandot körde i bakgrunden.
Jag väntade en sedan stund. Efter att jag gett
kommandot ls igen, skrev skalet ut att
bakgrundsjobbet var klart.
Förmodligen blev det klart några sekunder tidigare,
medan jag väntade. Skalet meddelar ju inte
användaren genast när ett bakgrundskommando är klart,
utan först när det får tillfälle att skriva ut en ny prompt.
Information och data kan skickas till ett program medan det kör. Programmet kan också skicka ut data. För att kunna hantera flödet av data har varje programkörning tre informationskanaler: standard indata, standard utdata och standard felmeddelanden. Vi ska nu berätta hur man med hjälp av skalet kan hantera dessa kanaler.
Det som skrivs ut efter att man gett ett kommando
kallas för kommandots utdata.
Vanligtvis skrivs utdatan direkt till skärmen,
men det händer ibland att man vill spara den i en fil.
Detta är lätt gjort: man skriver bara ''> filnamn''
någonstans i kommandot, lämpligen i slutet av det.$ date
tor feb 5 16:36:00 CET 1998
$ date > datum
$ ls
bellman datum dikter/ lenngren
$ cat datum
tor feb 5 16:36:08 CET 1998
$Ovan lät jag först date skriva ut tid och datum.
Som vanligt kom utskriften direkt på skärmen.
Sedan körde jag date igen, men med utdatan riktad
till filen datum.
Därefter hade jag fått en fil med namnet datum,
och vid en kontroll med cat såg jag att
utskriften från date hade hamnat där.
Vi ger ännu ett exempel:$ echo Hej > hejfil
$ ls
bellman datum dikter/ hejfil lenngren
$ cat hejfil
Hej
$Jag lät här echo skriva ordet ''Hej'' till en
fil med namnet hejfil.
Man kan ''slå ihop'' två eller flera filer genom att låta cat
skriva ut deras innehåll medan utdatan är riktad till en ny fil.$ cat hejfil datum > nyfil
$ ls
bellman datum dikter/ hejfil lenngren nyfil
$ cat nyfil
Hej
tor feb 5 16:36:08 CET 1998
$Om man använder > filnamn för att styra
utdatan från något kommando till en existerande fil
filnamn, så raderas innehållet i denna fil innan utdatan
skrivs till den.$ date > nyfil
$ cat nyfil
tor feb 5 16:55:27 CET 1998
$Filens nuvarande innehåll behålls,
och kommandots utdata läggs till på slutet, ifall
man skriver >> i stället för >:$ echo och hå. >> hejfil
$ cat hejfil
Hej
och hå.
$
Det är skillnad mellan ett kommandos utdata och dess eventuella
felmeddelanden. Vill man skicka felmeddelandena till
en fil, så ska man skriva 2> fil i stället för bara
> fil.$ cp datum
cp: destinationsfil saknas
Försök med "cp --help" för mer information.
$ cp datum > utdata
cp: destinationsfil saknas
Försök med "cp --help" för mer information.
$ cat utdata
$ cp datum 2> utdata
$ cat utdata
cp: destinationsfil saknas
Försök med "cp --help" för mer information.
$Först gav jag det ofullständiga kommandot cp datum,
och fick genom ett felmeddelande påpekat för mig att
kommandot var felaktigt. Därefter försökte jag dirigera om
utdatan till filen utdata, men detta påverkade inte
felmeddelandet. I tredje försöket lyckades jag däremot få felmeddelandet
att hamna i filen utdata genom att använda
2> i stället för >.
Från vissa kommandon kan det komma både utdata och felmeddelanden.
Man kan då skicka utdatan åt ett håll och felmeddelandena åt ett annat.$ wc lenngren bellmna
19 118 649 lenngren
wc: bellmna: Filen eller katalogen finns inte
19 118 649 total
$ wc lenngren bellmna > utdata 2> felmeddelande
$ cat utdata
19 118 649 lenngren
19 118 649 total
$ cat felmeddelande
wc: bellmna: Filen eller katalogen finns inte
$Ovan ''råkade'' jag stava ett filnamn fel.
Först behandlar wc filen lenngren,
därefter skrivs ett felmeddelande ut,
och sedan ges en sammanfattning.
Jag körde därefter samma kommando igen,
med utskriften riktad till filen utdata
och felmeddelandena riktade till filen
felmeddelande och kontrollerade att
allting hade hamnat rätt.
Om utdatan och felmeddelandena ska hamna på samma ställe,
så ska man omdirigera dem med tecknen >&:$ wc lenngren bellmna >& båda
$ cat båda
19 118 649 lenngren
wc: bellmna: Filen eller katalogen finns inte
19 118 649 total
$Här körde jag kommandot
ytterligare en gång, med utskrift och felmeddelanden
riktade till filen båda.
I vissa kommandon förekommer sekvenser i stil med 2>&1,
som riktar felmeddelandena åt samma håll
som utskriften är riktad åt.
Tecknen &1 kan läsas som ''den plats som
utdatan just nu skickas till''.
Siffran 1 är associerad med standrad utdata,
siffran 2 med standard felmeddelanden och siffran 0
med standard indata.
Vi kommer dock inte att ha användning för detta
förrän i de senare kapitlen.
Till vissa kommandon får man skriva in text, som
då kallas för indata till kommandot.
Så är exempelvis fallet med
wc om man inte anger något filnamn:$ wc
nu ska
vi se vad som händer. Här trycker jag C-d
2 7 29
$ Indatan till kommandot ovan är de två raderna text,
som jag skrev in vid tangentbordet.
Man markerar att indatan är slut genom att
antingen trycka C-d i början av en rad
eller trycka C-d två gånger i följd.
Men var försiktig: om man trycker C-d när skalet
förväntar sig ett kommando, så finns det risk
för att man blir utloggad -
skalet tror ju då att det är slut på dess indata, kommandona!
Utdatan från wc är raden som innehåller siffrorna 2, 7 och 29.
Många andra kommandon än wc, tex cat och more,
väljer också
att vänta på indata om man inte anger något filnamn.
Vill man att indatan ska komma från en fil istället för
att matas in från tangentbordet, så skriver man bara
''< filnamn'' före eller efter kommandot.$ wc < bellman
12 71 372
$ wc bellman
12 71 372 bellman
$Kan du se skillnaden mellan de båda kommandona?
Hur många tecken använder date för att ange dagens datum?
Vi kan ta reda på detta genom att använda wc
på filen datum (naturligtvis orkar vi inte själva
räkna tecknen).
Alltså: först kör man date och sparar undan dess utdata i en fil,
och sedan kör man wc på denna fil.
Om det bara är slutresultatet man är intresserad av, så känns det
kanske onödigt att gå omvägen via en fil; man vill att utdatan
från date ska gå direkt till wc. Detta kan man uppnå genom
att skriva ett lodrätt streck,
tecknet |, mellan kommandona; då skickar skalet
utdatan från första kommandot som indata till det andra.$ wc datum
1 6 30 datum
$ date | wc
1 6 30
$
En följd av kommandon som är sammankopplade med | kallas
för en rörledning.
Rörledningar är utomordentligt användbara.
Till exempel, om utdatan från ett kommando är för lång för att få
plats på skärmen så att man inte hinner läsa den innan den försvunnit,
så kan man låta den gå genom more.$ ls -l /bin | more
-rwxr-xr-x 1 root root 23968 maj 5 01:36 ae*
-rwxr-xr-x 1 root root 2716 maj 7 19:32 arch*
-rwxr-xr-x 1 root root 325548 aug 15 18:56 bash*
-rwxr-xr-x 1 root root 318612 jun 10 13:00 bash2*
-rwxr-xr-x 1 root root 9104 maj 9 01:06 cat*
-rwxr-xr-x 1 root root 9836 maj 10 01:46 chgrp*
-rwxr-xr-x 1 root root 10348 maj 10 01:46 chmod*
-rwxr-xr-x 1 root root 9652 maj 10 01:46 chown*
-rwxr-xr-x 1 root root 23200 maj 10 01:46 cp*
-rwxr-xr-x 1 root root 46712 feb 25 1997 cpio*
-rwxr-xr-x 1 root root 23232 maj 30 20:58 date*
--More--
Nu återstår det bara att städa upp efter oss...$ rm datum felmeddelande utdata båda hejfil nyfil
$
Ett antal tecken, bland andra
*, har en speciell mening för skalet.
Ibland kan detta ställa till problem.
Om jag exempelvis vill skriva ut texten
''Det mest använda jokertecknet är *'',
hur gör jag då?
Så här kan jag inte göra:$ echo Det mest använda jokertecknet är *
Det mest använda jokertecknet är bellman dikter lenngren
$Problemet är att skalet griper in och ändrar i det
kommando jag gav. Hur ska jag göra för att skydda mitt kommando
från skalets inblandning? Svaret är att jag ska ge mitt
kommando beskydd.
Med hjälp av beskydd tar man bort den speciella betydelse
vissa tecken har för skalet, och kan därigenom få dessa tecken
att ingå i argument till kommandon.
Det enklaste sättet att ge beskydd är att använda tecknet \,
det bakvända snedstrecket.
Det skyddar det tecken som följer efter det från att tolkas av skalet.
Så problemet med utskriften ovan kan lösas så här:$ echo Det mest använda jokertecknet är \*
Det mest använda jokertecknet är *
$Skalet skriver om kommandot ovan genom att ta bort beskyddet,
men det tecken som var skyddat skrivs inte om på något sätt.
Att skriva ut ett uttryck som 2 * 3 > 5 är lika enkelt:$ echo 2 \* 3 \> 5
2 * 3 > 5
$Så här skulle det gå ifall jag inte hade använt beskydd:$ echo 2 * 3 > 5
$ ls
5 bellman dikter/ lenngren
$ cat 5
2 bellman dikter lenngren 3
$ rm 5
$Skalet tolkade * som ett jokertecken och
riktade utdatan till en fil med namnet 5.
Vi har redan sett att det bakvända snedstrecket
har en speciell betydelse om det skrivs sist i en
kommandorad; det tolkas som att kommandot ska fortsätta
på nästa rad. $ echo Gub\
> ben Noach
Gubben Noach
$I princip plockar skalet bort
det bakvända snedstrecket och nyrad-tecknet från kommandot.
Men detta är enda undantaget - alla tecken utom
nyrad-tecknet skyddas från skalets inblandning om
de föregås av tecknet \.
Det bakvända snedstrecket kan till och med skydda sig självt:$ echo Beskydd ges av tecknet \\
Beskydd ges av tecknet \
$
Man kan skydda en hel textsträng
genom att omge den med apostrofer. Därigenom slipper man sätta
ett bakvänt snedstreck framför varje ''farligt'' tecken i strängen.
Skalet skriver om kommandot genom att ta bort apostroferna,
men det som stod inom apostroferna lämnas sedan intakt.$ echo 'Tecknen * och \ skyddas så här.'
Tecknen * och \ skyddas så här.
$ echo '2 * 3 > 5'
2 * 3 > 5
$
Med ett blanktecken menas ett mellanslag eller tabulatorsteg.
Om skalet påträffar en följd av nyrad-tecken eller blanktecken, så
plockas dessa bort från kommandot. Den enda effekten de har är att
de separerar argument.$ cp bellman Epistel21
$ ls
Epistel21 bellman dikter/ lenngren
$ rm Epistel21
$Att jag skrev flera mellanslag mellan bellman och
Epistel21 spelade ingen roll, kommandot exekverades
på samma sätt som om det bara hade funnits ett enda
mellanslag. Skalet noterade
att det första argumentet var bellman och det andra
var Epistel21, men sedan togs mellanslagen bort.
Därefter skickades argumenten till programmet cp,
som inte fick veta att det från början fanns flera mellanslag
mellan dem. På samma sätt går det här:$ echo bellman Epistel21
bellman Epistel21
$Skalet åt upp mellanslagen efter att argumenten hade separerats.
Sedan skickades de båda argumenten till echo,
som skrev ut dem med ett enda mellanslag som separator.
Men hur ska man då göra om man vill att ett argument
ska innehålla blanktecken eller nyrad-tecken?
Svaret på denna fråga är naturligtvis att man ska
ge dessa tecken beskydd gentemot skalet.$ echo 'bellman Epistel21'
bellman Epistel21
$ echo 'Apostrofer kan
> skydda nyrad-tecken.'
Apostrofer kan
skydda nyrad-tecken.
$
Genom att använda beskydd kan man få filnamn som innehåller
specialtecken, inklusive mellanslag och nyrad-tecken.
Detta rekommenderas inte, för ju konstigare tecken ett
filnamn innehåller, desto svårare blir det att hantera filnamnet.
Antag att vi ändå, mot bättre vetande, vill kopiera filen
bellman och ge kopian namnet Epistel 21.
Här är vårt första försök:$ cp bellman Epistel 21
cp: kopiering av flera filer, men sista argumentet (21) är inte en katalog
Försök med "cp --help" för mer information.
$Det gick inte så bra. Då skalet tolkar kommandot vi gav, tror det att
bellman, Epistel och 21 är tre separata argument.
Vi måste skydda mellanslaget mellan Epistel och 21
från skalet:$ cp bellman 'Epistel 21'
$ ls
Epistel 21 bellman dikter/ lenngren
$ ls -l
total 4
-rw------- 1 göran göran 372 feb 3 15:58 Epistel 21
-rw------- 1 göran göran 372 feb 1 16:48 bellman
drwxrwxr-x 2 göran göran 1024 feb 1 17:12 dikter/
-rw-rw-r-- 1 göran göran 649 feb 1 15:53 lenngren
$Den här gången gick det bättre. Tack vare att blanktecknet var
skyddat, delades inte Epistel 21 upp i två argument,
utan det sågs som ett enda. Vi måste skydda blanktecknet
varje gång vi hänvisar till filen Epistel 21:$ wc Epistel 21
wc: Epistel: Filen eller katalogen finns inte
wc: 21: Filen eller katalogen finns inte
0 0 0 total
$ wc Epistel\ 21
12 71 372 Epistel 21
$Vid kommandot wc Epistel 21 tolkades Epistel och 21
återigen som separata argument, och wc trodde då att
det rörde sig om två olika filnamn. I det följande kommandot,
där mellanslaget var skyddat (denna gång av ett bakvänt snedstreck),
sågs däremot Epistel 21 som ett enda filnamn.
När jag nedan raderar filen, demonstrerar jag ett tredje sätt
att skydda blanktecknet:$ rm Epistel' '21
$ ls
bellman dikter/ lenngren
$Man behöver alltså inte skydda hela texten med apostrofer,
bara de ''farliga'' tecknen.
Apostrofer skyddar alla tänkbara tecken, med ett undantag:
de kan inte skydda sig själva.
Man kan inte ha en apostrof mellan två andra, för då skulle ju den
första och den mellersta apostrofen tolkas som ett par.
Däremot kan apostrofer skyddas av
det bakvända snedstrecket:$ echo tag dig se\'n dito en
tag dig se'n dito en
$
Det beskydd som apostrofer
ger förändras ifall man sätter ett dollartecken före
den första apostrofen.
Uttryck som $'text' är alltså speciella.
I sådana uttryck fungerar
det bakvända snedstrecket som ett kommando.
Det hela går ut på att man ska kunna få
vilka tecken som helst att ingå i argument.
Till exempel skrivs \n om till ett
nyrad-tecken och \t till ett tabulatorsteg.$ echo $'den skönsta nymf, som åt dig ler,\n\tinunder armen tag.'
den skönsta nymf, som åt dig ler,
inunder armen tag.
$I tabell 3.2 anges vilka specialtecken som
kan skrivas så här.
På liknande sätt kan skriva vilket tecken som helst
genom att ange dess oktalkod.
I tabell 3.1 visas oktalkoden för samtliga skrivbara
tecken i den teckenuppsättning, ISO-8859-1, som används i
Sverige. Oktalkoden består av tre siffror. De två första
står i kolumnen till vänster i tabellen medan
den tredje, som ska ersätta symbolen x, står i den översta
raden.
(Den siffra som står under varje tecken kallas för dess
decimalkod. Vi kommer inte att ha användning
för decimalkoderna här.)
Till exempel har tecknet ë oktalkod 353, och
namnet ''Citroën'' kan skrivas så här:$ echo $'Citro\353n'
Citroën
$
|
|
Slutligen vill vi nämna att det finns ett tredje och
sista sätt att beskydda tecken och teckensträngar, nämligen att
omge dem med citationstecken.
Citationstecken fungerar ungefär som apostrofer, men de
ger inte ett lika säkert skydd.
Varken det bakvända snedstrecket,
dollartecknet,
den bakvända apostrofen ` eller citationstecknet självt
skyddas av citationstecken.
Det finns två skäl till att man ibland använder
citationstecken som skydd. Det ena skälet är
att man därigenom kan skydda
en textsträng som innehåller apostrofer.
Det andra, som vi ska återkomma till i
kapitel 6,
är att man med hjälp av citationstecken
kan få skalet att göra vissa, och undvika övriga,
av de vanliga omskrivningarna.$ echo "tag dig se'n dito en"
tag dig se'n dito en
$Om ett citationstecken ska skrivas ut, så måste det skyddas -
antingen av ett bakvänt snedstreck eller av apostrofer:$ echo 'Säg "hej" till farbror Göran!'
Säg "hej" till farbror Göran!
$Vill man ha ett dollartecken, ett bakvänt snedstreck
eller ett nytt citationstecken mellan två citationstecken, så ska
man ett bakvänt snedstreck som skydd.$ mening="En \"meningslös\" mening med \\ och \$"
$ echo $mening
En "meningslös" mening med \ och $
$
Det enklaste sättet att starta fönstersystemet X är att logga in via XDM; då kommer man automatiskt in i X. Figur 1.1 visar hur inloggningsskärmen kan se ut. På datorer som inte kör XDM måste man starta X manuellt med kommandot startx (eller möjligtvis xinit) från prompten efter att man loggat in genom en textterminal.
Vad som sker efter att man startat X beror på hur systemet är konfigurerat. I de flesta fall startas dock en så kallad fönsterhanterare. Fönsterhanteraren tillhandahåller bland annat en meny med vars hjälp man kan starta X-program, eller X-klienter som de kallas enligt gängse terminologi.
Bilden från en X-klient visas i ett (eller kanske flera) så kallade fönster på bildskärmen. Oftast är fönstren rektangulära. Bakgrunden på bildskärmen kallas för rotfönstret. Om man kör flera klienter samtidigt, så kan det bli många fönster på skärmen. I figur 4.5 finns det tre fönster (förutom rotfönstret) på bildskärmen, varav två delvis överlappar varandra.
Vanligtvis körs ett X-skal igång automatiskt när man startat X. Ett X-skal är helt enkelt ett fönster i vilket man kör sitt skal, så att man kan ge kommandon precis som vid skalet i en vanlig textterminal. Fönstret som X-skalet kör i kallas ibland för en terminalemulator eller för en pseudoterminal. Om inget X-skal startas automatiskt, kan man förmodligen starta ett med hjälp av fönsterhanterarens meny. Hur man hittar menyn beror återigen på konfigurationen, men ofta ska man flytta pekaren (den markör man styr med musen) till rotfönstret och trycka på en av musknapparna. Figur 4.1 visar hur menyn kan se ut. För att få fram ett X-skal ska man välja xterm eller något av de alternativ som finns under rubriken XShells.
Bilden: Fönsterhanterarens meny.
Ta fram ett X-skal nu! Ge kommandot$ xsetroot -solid Darkred
$vid prompten i X-skalet. Om det hela fungerar,
så blir rotfönstret mörkrött.
I stället för Darkred
kan man ta färger som
Green,
Yellow,
White,
Midnightblue
eller någon av de hundratals andra
som finns angivna i filen
/usr/lib/X11/rgb.txt
(kommandot showrgb skriver ut dem).
Programmet xclock visar helt enkelt en klocka i ett
fönster. Ge kommandot xclock & i ett
X-skal för att prova programmet!
Figur 4.2 visar hur det ser ut.
Det är viktigt att man skriver tecknet &
efter xclock.
Skälet är att prompten i X-skalet inte
återvänder
förrän ett givet kommando är klart
om man inte avslutar kommandot med &.
Kommandot xsetroot tar mycket kort
tid för datorn att köra, så man behöver inte
starta det som en bakgrundsprocess.
Om man råkar glömma tecknet & efter ett
kommando som kör i evighet, så blir
X-skalet oanvändbart.
Man kan naturligtvis starta ett nytt skal då.
Men man kan också avsluta processen med
C-c. Eller man kan tillfälligt stoppa den
med C-z och därefter köra igång den
i bakgrunden med kommandot bg,
varefter X-skalet åter blir användbart.
X tillhandahåller en klippbuffert. Detta innebär att man kan måla över ett stycke text i ett fönster genom att föra pekaren över texten med vänsterknappen intryckt. Texten kan klistras in någon annanstans genom att man trycker på musens mittknapp.
Vad som händer inuti ett fönster, och hur det ser ut där, sköter den enskilda klienten; samspelet mellan de olika fönstren kontrolleras av fönsterhanteraren. Det går att köra X utan någon fönsterhanterare, men då förloras mycket av funktionaliteten. Det finns många fönsterhanterare att välja mellan. Man kan bara köra en fönsterhanterare i taget, men det går utmärkt att stoppa en fönsterhanterare, och köra igång en annan, mitt i en X-session. Systemadministratören kan konfigurera de flesta av fönsterhanterarens funktioner, och varje användare kan ändra konfigurationen för sin egen del. Därför kan det vara svårt att förutsäga exakt vilka tjänster som erbjuds av fönsterhanteraren. Men vi ger ändå några exempel på vad man kan förvänta sig:
Bilden: Programmet xcalc, utan dekoration.
Bilden: Programmet xcalc, dekorerat av fönsterhanteraren FVWM2.
Bilden: Programmet xfontsel, dekorerat av TWM.
Bilden: Programmet xfontsel, dekorerat av OLVWM.
Bilden: Programmet xfontsel, dekorerat av FVWM95.
Det finns ett antal standardflaggor som många, om än inte alla, X-klienter kan ta emot. En förteckning över dem finns i tabell 4.1. Med deras hjälp kan man till exempel ange storlek och position för klientens fönster samt välja färg på text och bakgrund. Vi ska i detta avsnitt ge en inledande beskrivning av hur standardflaggorna kan användas.
|
Grafiken i X är baserad på punkter. Detta är något som kan vålla problem eftersom punkterna är olika stora på olika bildskärmar. Om antalet punkter är stort i förhållande till skärmens storlek, så säger man att skärmen är högupplösande. Antal punkter som visas på skärmen kan till exempel vara 1024x768, dvs 1024 punkter horisontalt och 768 punkter vertikalt. En högupplösande skärm kan visa 1600x1200 eller fler punkter, medan en lågupplösande kan visa 640x480 eller tom ännu färre punkter. Punkterna på en högupplösande skärm är mindre än punkterna på en lågupplösande skärm, så ett fönster som är tex 600 punkter brett och 400 punkter högt blir mindre på en högupplösande skärm än på en lågupplösande. Ett tolvpunkters typsnitt blir också mindre på en högupplösande skärm.
Lyckligtvis tillåter de flesta X-klienter
att man ändrar storleken på fönstren.
Därigenom kan man välja ett utseende som
passar den egna bildskärmen.
För att ändra fönsterstorleken
tar man hjälp av fönsterhanteraren.
Men man kan ofta också ange önskad storlek
med flaggan -geometry
redan när klienten startas.
Fönstrets storlek specificeras som
breddxhöjd.
Vilken enhet som används för bredd
respektive höjd avgör den enskilda klienten.
Oftast anges de i antal punkter, men för
vissa textbaserade
program som Emacs och X-skalet xterm
anges de i antal rader respektive kolumner text.
Standardstorleken för klockan xclock är
164x164
punkter. För att få storleken
150x100
punkter startar vi programmet i stället med kommandot
xclock -geometry 150x100 &.
Det går också att ange fönstrets position på
skärmen.
Först anger man horisontalt läge.
För att placera fönstret tex 210 punkter från vänster
skriver man +210.
Detta innebär att avståndet mellan bildens vänstra kant
och fönstrets vänsterkant är 210 punkter.
Om man i stället skriver -175, så placeras
fönstret 175 punkter från höger, dvs antalet
punkter från fönstrets högerkant till bildens högra
kant blir 175.
På motsvarande sätt anges det vertikala läget.
Tex betyder -50 att fönstrets nedre kant
ska vara 50 punkter från bildens nedre kant.
Kommandot xclock -geometry -20+10 & placerar
klockfönstret nära det övre högra hörnet av bildskärmen,
20 punkter till vänster och 10 punkter ner.
Naturligtvis kan man ange både storlek och position för
en klient. Tex ger kommandot$ xclock -geometry 100x100+0-0 &
$en klocka av storlek
100x100
i det nedre vänstra hörnet.
Ofta tillåter X-klienterna att man använder förkortningar i flaggorna ifall det inte ger upphov till tvetydigheter. Förutom geometry finns det ingen flagga som xclock använder och som börjar på ''g'', så kommandot ovan kan också skrivas xclock -g 100x100+0-0 &. Om det tex hade funnits en flagga med namnet getstr, så skulle man kunna förkorta -geometry till -geo men inte till -g eller -ge.
Med förgrunden i ett fönster
menas vanligtvis texten.
Vissa utritade detaljer som tex
tim- och minutstrecken i xclock
kan också höra till förgrunden.
Det som inte är förgrund kallas för
bakgrund.
Många X-program tillåter att man
anger för- och bakgrundsfärg med flaggorna
-fg respektive -bg.
Prova tex$ xclock -fg DeepSkyBlue -bg Yellow &
$Flaggan -rv växlar förgrundsfärg mot bakgrundsfärg
och omvänt. Som exempel rekommenderas återigen
xclock, dvs prova kommandot xclock -rv.
När du fått för många klockor på skärmen
kan det vara lämpligt att ge kommandot killall xclock.
Programmet xsetroot
är till för att ändra rotfönstrets egenskaper -
inte enbart dess färg. Man kan också använda det för
att byta utseende samt för- och bakgrundsfärg på
pekaren.
Prova tex$ xsetroot -cursor_name pirate -bg Black -fg Yellow
$Flytta sedan pekaren till rotfönstret, så
ser du pekaren ''Pirate'' i gult med svart ram.
Namnen på alla tillgängliga pekare räknas up
i tabell 4.2. Kommandot
xfd -fn cursor ger ett fönster med bilder av
samtliga dessa markörer.
|
Med hjälp av flaggan -fn kan man välja fonter (eller typsnitt) för den text som skrivs ut av X-klienterna. Man kan också välja fonternas storlek, lutning och tjocklek etc.
Programmet xlsfonts skriver ut vilka fonter
som finns tillgängliga.
Som synes nedan finns det 1403 stycken fonter på
min dator. Därför tar jag bara med de första 10 raderna
av utskriften från xlsfonts.$ xlsfonts | wc
1403 1643 77534
$ xlsfonts | head
-adobe-courier-bold-i-normal-0-0-0-0-m-0-iso8859-1
-adobe-courier-bold-o-normal-0-0-100-100-m-0-iso8859-1
-adobe-courier-bold-o-normal-0-0-75-75-m-0-iso8859-1
-adobe-courier-bold-o-normal-10-100-75-75-m-60-iso8859-1
-adobe-courier-bold-o-normal-10-100-75-75-m-60-iso8859-1
-adobe-courier-bold-o-normal-11-80-100-100-m-60-iso8859-1
-adobe-courier-bold-o-normal-11-80-100-100-m-60-iso8859-1
-adobe-courier-bold-o-normal-12-120-75-75-m-70-iso8859-1
-adobe-courier-bold-o-normal-12-120-75-75-m-70-iso8859-1
-adobe-courier-bold-o-normal-14-100-100-100-m-90-iso8859-1
Brutet rör
$Varje rad ovan är namnet på ett typsnitt.
För att se hur typsnittet font ser ut
kan man ge kommandot xfd -fn font.
Som exempel på hur fonter används
tar vi programmet xclock, men med digital tidsvisning
i stället för analog. Kommandot
xclock -digital & startar en digitalklocka
som uppdateras en gång i minuten. (Flaggan kan, som nedan, förkortas till
-d.)
Prova det kommandot, och jämför sedan
tex med följande kommando:
xclock -d -fn -adobe-courier-bold-o-normal--12-120-75-75-m-70-iso8859-1Naturligtvis är det är otympligt att skriva så långa kommandon. Ett enklare sätt är att använda resurser, något vi berättar om i avsnitt 4.4. Men vad betyder de olika fälten i fontnamnet?
* i ett fält
om det inte spelar någon roll vilket värde det blir.
I så fall får man den första fonten som X
hittar och som matchar den fontsträng man angett.
Många av fälten hänger ihop, värdena i vissa fält beror på värdena i andra. Därför kan man inte bara dikta upp en fontsträng och tro att det ska finnas en sådan font. I stället kan man försöka finna en font men hjälp av xlsfont. Men det finns ett annat, bättre sätt: programmet xfontsel, se figur 4.4. Programmet startas med kommandot xfontsel &. Inne i programmet får man via menyer välja värden i de olika fälten, och så fort något värde ändrats får man se ett smakprov av tecken från den font man valt. Man får bara välja bland existerande fonter. När man funnit en font man är nöjd med kan man klicka på knappen ''Select'' i xfontsel-fönstret. Då kopieras fontsträngen in i X-klippbufferten, så att man kan klippa in den tex i ett X-skal eller i en textredigerare.
Några flaggor gäller fönstrens dekoration. Vilken effekt dessa har beror på hur fönsterhanteraren väljer att hantera dem. Tex är flaggan -bd Green en önskan om att ramen kring fönstret ska vara grön, och -bw 10 att ramen ska vara 10 punkter bred. Men de flesta fönsterhanterare struntar i denna anvisning och ritar sin egen ram i stället. (Prova att köra utan någon fönsterhanterare, och ge tex kommandot xterm -bd Green -bw 10 &.) Flaggan -title ger fönstret en ny titel, som fönsterhanteraren skriver ut i titelraden på vissa av fönstren. Som exempel kan man ta xterm -title X-skal &.
Flaggan -iconic uttrycker en önskan om att fönstret ska startas som en ikon. Vilken effekt denna flagga får beror på fönsterhanteraren. Ett exempel är xterm -iconic &.
Vad flaggan -display används till berättar vi i avsnitt 4.3. Flaggorna -xrm och -name återkommer vi till i avsnitt 4.5.
Användaren för in data och signaler till X genom ett tangentbord och ett pekdon. Vanligtvis är pekdonet en mus med tre knappar. Kommunikationen från X till användaren sker genom bildskärmen. En uppsättning av ett tangentbord och en mus som kontrollerar en eller flera bildskärmar kallas för en display. Om det finns fler än en bildskärm i en display, så behöver skärmarna inte visa samma bild, men de styrs som sagt av samma tangentbord och mus. De flesta displayer har dock bara en bildskärm, som i figur 4.5.
X-klienter har inte tillgång till displayen direkt, utan all kommunikation går via X-servern, ett så kallat systemprogram som kör på den dator displayen är kopplad till. Servern avläser signaler från tangentbord och mus och förmedlar dem till klienterna, och på begäran från klienterna ritar servern fönster och annan grafik på bildskärmen via grafikkortet.
X tillåter att man har flera displayer kopplade till en och samma dator. Man måste i så fall köra en separat X-server för varje display. Då varje display kräver sitt eget tangentbord och sin egen mus är det ovanligt att datorer har mer än en display. Men liksom en enda terminal kan tjäna som flera virtuella terminaler som man växlar mellan genom att trycka Ctrl och Alt samt någon av tangenterna F1 till F6, kan man också ha flera virtuella displayer som man växlar mellan genom att trycka Ctrl och Alt samt någon av tangenterna F7, F8 osv. Det krävs mycket minne för att datorn ska kunna hantera flera virtuella displayer. Den första displayen på den lokala datorn heter :0 (dvs ett kolon följt av siffran noll). Den andra displayen heter :1, den tredje :2 osv. Återigen bör vi poängtera att man oftast bara har en display per dator, och att den heter :0. Om mer än en bildskärm är kopplad till samma display, så skiljer man på de olika skärmarna genom att ange en punkt och skärmens nummer efter diplayens namn. Den första skärmen har nummer noll, den andra har nummer ett osv. Den andra bildskärmen på tredje displayen heter alltså :2.1. Om man utelämnar bildskärmens nummer, och skriver tex :2, så förutsätts det att man menar bildskärm nummer noll. Om man vill referera till en display som finns på en annan dator än den lokala, så anger man bara datorns namn eller IP-nummer före kolonet, tex fasolt:0 eller fasolt.turangalila.se:2.1 eller 192.168.1.1:0.0.
För att starta en X-server på (den virtuella) displayen :1 ska man från en virtuell terminal ge kommandot startx - :1 eller tex X -indirect localhost :1 -bpp 16.
X är ett nätverksbaserat fönstersystem. Klienterna kan köra på en annan dator än den som servern kör på och som bildskärmen är kopplad till. Under X kan man köra några klienter lokalt (dvs på den dator man sitter vid och som servern kör på), och andra klienter på flera andra datorer om man så vill. Klienterna utnyttjar då datorkraft från de andra datorerna, medan själva bilden som klienterna visar upp skickas till den egna bildskärmen. Kommunikationen mellan klienterna och servern går över nätverket, i ett slags språk (kallat för X-protokollet) som är oberoende av datorarkitektur och operativsystem. Så det har ingen betydelse vilken slags dator klienterna kör på; en X-klient på tex en Sun-dator kan visa sin bild på en Linuxdator och vice versa. Användaren behöver inte vara medveten om att vissa program kör på en avlägsen dator, man kan inte se någon skillnad jämfört med om de kör lokalt. Inte heller behöver programmen ''vara medvetna om'' att deras bild visas på en annan dator. Därför kan det sägas att X är integrerat med nätverket på ett genomskinligt sätt.
I figur 4.6 sitter jag vid datorn fafner. Jag kör en X-klient lokalt (fönster A). Dessutom kör jag ett X-program på fasolt, och detta program har instruerats att visa sin bild på displayen fafner:0 (fönster B). Vilken användare som helst på vilken dator som helst på nätverket, inklusive Internet, kan starta en X-klient på min display ifall jag tillåter det. Omfattande säkerhetsanordningar finns dock inbyggda i X för att skydda användare från obehöriga intrång.
Det enklaste och i särklass bästa sättet
att köra X över nätverket är att
från den dator man sitter vid
(låt oss anta att den heter fafner)
logga in på
den andra datorn (vi antar att den heter fasolt)
med programmet ssh.
Därefter kan man starta X-klienter på fasolt,
och bilden hamnar automatiskt på displayen på fafner.$ ssh fasolt -l kobjer
kobjer@fasolt's password:
Last login: Thu Feb 12 00:01:36 1998 from fafner.turangali
Linux fasolt 2.0.31 #1 Sat Nov 1 15:52:35 CET 1997 i586 unknown
$ xclock &
[1] 12636
$Så enkelt var det att logga in som användaren kobjer på
fasolt och starta X-klienten xclock.
Programmet ssh finns inte installerat på
alla datorer, så ibland fungerar inte metoden ovan.
Då tvingas man logga in på fasolt med telnet eller
rlogin. Man bör vara medveten om att
dessa program skickar all information i klartext
över nätverket, så det är lätt för inkräktare att
avlyssna kommunikationen.
I motsats till ssh gör inte telnet och rlogin
automatiskt två nödvändiga inställningar.
Den ena av dessa
inställningar är att fasolt ska instrueras att visa
sin bild på displayen fafner:0.
Detta kan man göra genom att ge kommandot
export DISPLAY=fafner:0 på fasolt
eller genom att använda standardflaggan -display fafner:0
varje gång en X-klient startas på fasolt.
Den andra inställningen är att användaren kobjer på
fasolt måste känna till en hemlig kod för
displayen fafner:0 för att få tillgång till den.
Vi kan ta reda på hur den hemliga koden
ser ut genom att på fafner
ge kommandot xauth list fafner:0.
Efter att ha loggat in på fasolt med telnet
använder vi xauth igen för att överlämna koden till
fasolt:$ xauth list fafner:0
fafner.turangalila.se:0 MIT-MAGIC-COOKIE-1 5f3c426a0e2335427a6f6e3641616761
$ telnet fasolt
fasolt login: kobjer
Lösenord:
Linux fasolt 2.0.31 #1 Sat Nov 1 15:52:35 CET 1997 i586 unknown
$ xauth add fafner:0 . 5f3c426a0e2335427a6f6e3641616761
$ xclock -display fafner:0 &
[1] 12646
$Genom att ta hjälp av X-klippbufferten
slipper man skriva av koden ''för hand''.
Så här går det om man inte för över den hemliga koden:$ rlogin fasolt -l kobjer
Lösenord:
Linux fasolt 2.0.31 #1 Sat Nov 1 15:52:35 CET 1997 i586 unknown
$ xclock -display fafner:0
Xlib: connection to "fafner:0.0" refused by server
Xlib: Invalid MIT-MAGIC-COOKIE-1 key
Error: Can't open display: fafner:0
$
Den hemliga koden lagras i en fil med namnet .Xauthority i ens hemkatalog. I lokala nätverk brukar hemkatalogen vara densamma oberoende av vilken dator man loggar in på, och i så fall slipper man föra över den hemliga koden - den är ju då redan tillgänglig på de andra datorerna.
På datorer som inte heller kan hantera hemliga koder återstår bara den sämsta metoden, nämligen xhost. Den kan bara användas ifall säkerhet inte spelar någon som helst roll. Om jag på fafner ger kommandot xhost +fasolt, så får alla användare på fasolt tillgång till min display. Då kan jag logga in på fasolt och starta mina X-klienter. Därefter bör jag från fafner ge kommandot xhost -fasolt så att inga fler X-klienter kan komma åt min display från fasolt. (Ibland krävs också att man skapar en .rhosts-fil, se man rhosts. Detta är ungefär detsamma som att rulla ut röda mattan för hackers.) Kommandot xhost + ger hela nätverket obegränsad tillgång till den egna displayen, något som dock inte rekommenderas...
Vi har sett att man med hjälp av flaggor på kommandoraden kan välja sådant som de olika fönstrens storlek, bakgrundsfärg och färg på text och annan förgrund. Det blir dock på tok för jobbigt om man måste skriva in alla flaggor varje gång. Och visst finns det ett bättre sätt att konfigurera X-klienterna! Inställningarna görs med hjälp av ett oerhört kraftfullt system som kallas för resurser. Som vanligt i UNIX-sammanhang är detta system tyvärr också oerhört komplicerat, och det krävs tålamod om man ska kunna lära sig behärska det.
Vi ska ta programmet xclock som ett exempel i denna inledande diskussion av resurser. I bruksanvisningen till xclock (ge kommandot man xclock för att läsa den) står det bland annat följande:
X DEFAULTS
This program uses the Clock widget. It understands all of
the core resource names and classes as well as:
width (class Width)
Specifies the width of the clock. The default for
analog clocks is 164 pixels; the default for digi
tal clocks is whatever is needed to hold the clock
when displayed in the chosen font.
height (class Height)
Specifies the height of the clock. The default
for analog clocks is 164 pixels; the default for
digital clocks is whatever is needed to hold the
clock when displayed in the chosen font.
update (class Interval)
Specifies the frequency in seconds at which the
time should be redisplayed.
foreground (class Foreground)
Specifies the color for the tic marks. The default
is depends on whether reverseVideo is specified.
If reverseVideo is specified the default is
lwhite, otherwise the default is black.
hands (class Foreground)
Specifies the color of the insides of the clock's
hands. The default is depends on whether reverseV
ideo is specified. If reverseVideo is specified
the default is lwhite, otherwise the default is
black.
highlight (class Foreground)
Specifies the color used to highlight the clock's
hands. The default is
depends on whether reverseVideo is specified. If
reverseVideo is specified the default is lwhite,
otherwise the default is black.
analog (class Boolean)
Specifies whether or not an analog clock should be
used instead of a digital one. The default is
True.
chime (class Boolean)
Specifies whether or not a bell should be rung on
the hour and half hour.
padding (class Margin)
Specifies the amount of internal padding in pixels
to be used. The default is 8.
font (class Font)
Specifies the font to be used for the digital
clock. Note that variable width fonts currently
will not always display correctly.
Vi ska undan för undan förklara vad allt detta innebär.
Men först ska vi naturligtvis visa vad man kan ha för
nytta av det!
Skapa därför en fil, som tex kan heta resurstest,
och som innehåller följande:xclock.clock.analog: True xclock.clock.height: 80 xclock.clock.width: 80 xclock.clock.padding: 4 xclock.clock.foreground: Black xclock.clock.hands: Black xclock.clock.highlight: Black xclock.clock.update: 1 xclock.clock.chime: TrueDen första raden anger att vi vill att klockan ska vara analog i stället för digital. De båda följande raderna ger storleken (antal punkter) för det fönster klockan ska visas i. Den fjärde raden anger avståndet (antal punkter) från kanten av klockans bild till kanten av det fönster klockan ritas i. Sedan kommer färgen på de små streck som markerar timmar och minuter på urtavlan. Raderna sex och sju ovan anger färg för klockans visare; en inre färg (rad sex) och en kantfärg (rad sju). Det åttonde raden anger intervallet (i antal sekunder) mellan uppdateringarna av klockan. Den sista raden anger att klockan ska tuta till varje hel- och halvtimme.
För att få xclock att följa dessa anvisningar ska vi läsa in filen till X med kommandot xrdb -load resurstest. Gör det, och starta sedan en ny xclock. Ser du att klockfönstret har blivit mindre och att det nu finns en sekundvisare? Ändra nu några av värdena i filen resurstest - välj några snyggare färger eller en annan storklek. Ge därefter åter kommandot xrdb -load resurstest och starta en ny klocka. När du har funnit de inställningar du tycker bäst om, vill du kanske att de ska finnas tillgängliga varje gång du loggar in på nytt? Lägg i så fall in raderna från filen resurstest i en fil med namnet .Xresources i din hemkatalog - om det finns en sådan fil, så läses den nämligen in då du startar X. Det finns en annan resursfil, /etc/X11/Xresources, som systemadministratören sköter. Den är gemensam för alla användare, och den läses in före den privata .Xresources. Filerna heter iallafall så på Debiansystem. På din dator kanske namnen är något annorlunda; granska startfilerna för X eller fråga systemadministratören för att få veta exakt. Nåväl, skriv nu in resurserna för X-clock i din privata resursfil, gå ur X och starta om. Kör sedan xclock och kontrollera att dina ändringar har trätt ikraft.
I de resursfiler som xrdb ska läsa in förekommer rader av formen
resursvariabel: värde
Resursvariabeln kan tex heta xclock.clock.hands,
och värdet kan tex vara Black.
Syntaxen för namnet på en resursvariabel är
klientResursvariabeln är uppbyggd av två eller fler ord som separeras av punkter. Det första ordet är ett namn på klienten, vanligtvis identiskt med namnet på det kommando som startar klienten - som tex xclock. Man kan ta reda på klientnamnet för ett visst fönster genom att ge kommandot xprop och sedan klicka på fönstret. Då spottas en sida text ut. Texten ger information om fönstret, bla en rad i stil med.objekt.delobjekt (...).attribut
WM_CLASS(STRING) = "xclock", "XClock"Detta betyder att man kan använda såväl xclock som XClock som namn för klienten. Många fönsterhanterare har en liknande funktion; om man tex väljer FvwmIdent i fönsterhanterarens meny och sedan klickar på något fönster, så får man information om detta fönster.
Det sista ordet i resursvariabeln, attributet, är namnet på en egenskap hos klienten (eller någon del av klienten). I vårt exempel förekommer attribut som height (höjden), update (tidsintervall i sekunder mellan successiva uppdateringar av klockan) och hands (visarnas färg).
Mellan första och sista ordet av namnet på en resursvariabel kan det förekomma ett eller flera ord, som anger vilken del av klienten som resursvariabeln syftar på. I stället för ''del'' säger man ofta ''objekt'' eller, som i bruksanvisningen ovan, ''widget''. I exemplet med xclock förekommer det enda objektet clock. Men i mer komplicerade fall, som vi diskuterar i avsnitt 4.5, kan det finnas flera objekt. Objekt kan också vara sammansatta av flera mindre delar, delobjekt, som i sin tur kan ha flera delar osv.
Resursvariabelns värde kan vara en textsträng, tex Black. Eller det kan vara ett tal, som 80. Det kan också vara ord som True (dvs sann) eller False (dvs falsk).
När man läser in en resursfil med xrdb -load, tas alla tidigare resursdefinitioner bort. Om man i stället använder xrdb -merge resursfil, så behålls alla gamla definitioner och de nya läggs till de gamla. Oftast ska man använda -merge i stället för -load.
Man får använda jokertecknet *
i resursnamnen. Vanligtvis är tex
xclock*hands: Green xclock*chime: Falseatt föredra framför att skriva ut resursvariablernas namn fullständigt.
Katalogen /usr/lib/X11/app-defaults innehåller resursfiler som ger grundkonfigurationer för ett antal olika X-klienter. Man kan få tips om hur klienten kan konfigureras genom att titta där. Om man vill ändra något värde som står där, så ska man klippa ut definitionen därifrån, klista in den i sin .Xresources och ändra värdet till det man önskar.
Vi ska i detta avsnitt berätta slutet på sagan om X-resurser.
Ett bra exempel på en X-klient med mer sammansatta objekt är xfontsel. Hela dess fönster betraktas som ett objekt med namnet pane. Detta objekt är sammansatt av fem delobjekt, nämligen commandBox, fieldBox, fontName, viewPort och grip.
Det första delobjektet, commandBox, omfattar den översta raden av fönstret. Detta delobjekt har i sin tur tre delar. En del (med namnet quitButton) är rutan till vänster där det står ''quit''. En annan del (med namnet ownButton) är rutan där det står ''select''. Den tredje och sista delen (med namnet countLabel) är texten längst till höger, den som säger ''4 names match'' i bild 4.4.
Det andra delobjektet, fieldBox, omfattar fönstrets andra rad. Det har i sin tur femton delobjekt. Fjorton av delobjekten (med namnen field0, field1 osv) representerar de olika fälten i en fontsträng. Varje sådant fält föregås av ett streck (eller ett minustecken). Det femtonde delobjektet, med namnet dash, representerar dessa streck. Exempelvis gör resursdefinitionerna
xfontsel.pane.fieldBox.field0.background: Blue xfontsel.pane.fieldBox.field0.foreground: White xfontsel.pane.fieldBox.field0.label: varumärkeatt fältet längst till vänster blir blått med texten ''varumärke'' i vitt. Prova dem gärna - dvs läs in dem med xrdb och starta sedan en ny xfontsel!
Tredje delobjektet av pane är fontName. Det omfattar tredje raden i xfontsel-fönstret, där den valda fontens namn finns utskrivet.
Det fjärde delobjektet, viewPort, omfattar den nedre halvan av fönstret. I detta fält finns en exempeltext som är skriven med den valda fonten.
Det femte delobjektet, grip, består av de små handtagen till höger i xfontsel-fönstret. Med deras hjälp kan man ändra storleken på de olika delarna av fönstret genom att man flyttar pekaren till någon av dem, håller in musens vänsterknapp och samtidigt flyttar musen uppåt eller nedåt.
Programmet editres kan rita diagram
över objektstrukturen för X-klienter.
I figur
visas en liten del
av objektstrukturen för
xfontsel. Några attribut för field0
finns också med där.
Antag att vi vill ha vit text och blå bakgrund på alla de fjorton fält som är delobjekt i fieldBox. Det går visserligen att sätta värden för varje fält för sig, på samma sätt som vi gjorde med det första fältet, men det är otympligt. Det finns dock ett smidigare sätt. Varje objekt (och varje delobjekt) tillhör nämligen en klass. En klass innehåller ibland bara ett, ibland flera objekt. De fjorton fälten field0, field1 osv bildar tillsammans en klass med namnet MenuButton. Om vi skriver MenuButton i stället för field0, så gäller definitionen för alla de fjorton fälten. Prova alltså det här:
xfontsel.pane.fieldBox.MenuButton.background: Blue xfontsel.pane.fieldBox.MenuButton.foreground: White
Klassnamn börjar alltid med stor bokstav, objektnamn börjar aldrig med stor bokstav. Därigenom blir det lätt att skilja mellan klasser och objekt. Detta förklarar den märkliga formen på objektnamn som fieldBox: det måste börja med liten bokstav eftersom det annars skulle se ut som ett klassnamn. När objektnamn är sammansatta av flera ord, tex ''field'' och ''box'', brukar alla orden utom det första skrivas med stor bokstav.
Men om vi nu vill att fälten ska ha blå bakgrund, med undantag för det sjunde fältet som ska ha röd bakgrund för att synas bättre? Det är enkelt, lägg bara till en rad som säger att field6 ska ha röd bakgrund. Om man anger värden både för klassen och för ett enskilt objekt, så gäller det värde man satte för objektet. Detta följer en allmän regel för hur resurser tolkas: om flera olika definitioner påverkar samma attribut, så prioriteras den resurssträng som är mest specifik.
Prova nu att läsa in resursdefinitionerna
xfontsel.pane.fieldBox.MenuButton.background: Blue xfontsel.pane.fieldBox.MenuButton.foreground: White xfontsel.pane.fieldBox.field6.background: Red xfontsel.pane.fieldBox.field6.label: storlekFöljden blir att alla fält utom det sjätte får blå bakgrund och vit text. Det sjätte fältet får röd bakgrund samt texten ''storlek'' i vitt.
Också attributen tillhör klasser. Från utdraget av bruksanvisningen till xclock kan vi se att attributen foreground, hands och highlight alla tillhör klassen Foreground. Definitionen xclock.clock.Foreground: Blue gör att hela förgrunden i xclock, dvs tim- och minutstreck samt visarna, blir blå. Om vi dessutom gör definitionen xclock.clock.hands: Green, så blir det inre av visarna grönt medan tim- och minutstreck samt kanten på visarna förblir blått.
Antag nu att vi vill att hela bakgrunden i xfontsel ska vara blå. Ett sätt att uppnå detta är att ta alla resursvariabler med attribut background och ge dem värdet Blue. Så här blir det då:
xfontsel.pane.commandBox.background: Blue xfontsel.pane.commandBox.countLabel.background: Blue xfontsel.pane.commandBox.ownButton.background: Blue xfontsel.pane.commandBox.quitButton.background: Blue xfontsel.pane.fieldBox.background: Blue xfontsel.pane.fieldBox.dash.background: Blue xfontsel.pane.fieldBox.MenuButton.background: Blue xfontsel.pane.fontName.background: Blue xfontsel.pane.viewPort.sampleText.background: BlueDetta är onödigt komplicerat. Återigen finns ett enklare sätt: man kan använda jokertecknet
*.
Då räcker det att göra så här:xfontsel*background: BlueSom synes i tabell 4.1, så har flaggan -bg Blue exakt samma effekt.
Den första av definitionerna
xfontsel*background: Blue xfontsel.pane.fieldBox.field6.background: Redsäger att all bakgrund ska vara blå, den andra säger att bakgrunden i sjunde fältet i fontsträngen ska vara röd. Så vilken färg blir det i det sjunde fältet? Jo, den blir röd - helt i linje med principen att den mer specifika definitionen ska ha företräde.
Mycket ofta använder man jokertecknet helt enkelt för att slippa skriva ut objektnamnet - antingen för att man inte orkar kolla upp exakt vad det heter, eller för att det blir för långt att skriva. Så till exempel brukar man föredra
xfontsel*field0.label: varumärke xfontsel*field6.label: storlekframför att skriva ut resursvariablernas namn fullständigt. Det finns ytterligare ett skäl till detta: om det kommer en ny version av tex xclock, så kanske man lägger in ytterligare någon nivå i objekthierarkin - kanske nivån face mellan clock och attributet. I så fall ändras resursvariablernas namn, till xclock.clock.face.hands osv. Då fungerar fortfarande xclock*hands, och man slipper göra ändringar i sina resursfiler.
Vanligtvis är det så att alla egenskaper hos en X-klient som kan ställas in med hjälp av flaggor på kommandoraden, också kan ställas in med hjälp av resurser. Däremot kan man ofta göra saker med resurser som inte går att göra med flaggor.
Två av standardflaggorna från tabell 4.1 har med resurser att göra, nämligen -xrm och -name.
Flaggan -xrm läser helt enkelt in en resursdefinition.
Ett exempel är$ xfontsel -xrm 'xfontsel*field6.label: storlek' &
$Skälet till att man kan behöva använda flaggan -xrm
är just att det kan finnas vissa egenskaper som kan ställas in
med hjälp av resurser men inte med hjälp av flaggor.
Genom att använda -xrm slipper man skriva in
resursdefinitionen i en fil.
Flaggan -xrm används inte särskilt ofta. En annan standardflagga, -name, är desto intressantare. I stället för att orda så mycket om den ska vi ge ett exempel. Läs först in definitionerna
xclock.clock.analog: True xclock.clock.hands: Green xclock.clock.update: 1 digitalur.clock.analog: False digitalur.clock.font: -*-courier-bold-r-*--18-*-75-75-m-*-iso8859-1med hjälp av xrdb. De tre första definitionerna gäller programmet xclock medan de båda sista gäller en X-klient med namnet digitalur. Ge nu kommandona$ xclock &
Poängen med flaggan -name är att den kan användas som i exemplet ovan. Den behövs då man har två (eller fler) standardkonfigurationer för en viss X-klient, och vill ha än den ena, än den andra konfigurationen. Då ger man helt enkelt varje konfiguration ett namn, som tex digitalur, och tar med flaggan -name digitalur vid de tillfällen då man föredrar just den konfigurationen.
En defekt med digitalklockan är att den bara uppdateras en gång i minuten. Vi skulle vilja att den också uppdateras varje sekund. Raden digitalur.clock.update: 1 ordnar detta. Men det finns ett annat sätt, som vi nu ska beskriva. Vi minns att varje komponent i namnet på en resursvariabel tillhör någon klass. Detta gäller också för den första komponenten i resursvariabeln, dvs klientens namn. Varje X-klient har alltså ett klassnamn.
Varje xclock-process tillhör klassen XClock, oavsett om processen heter xclock, digitalur eller något annat. Detta fungerar precis som då attributen foreground, hands och highlight alla tillhör klassen Foreground.
Om vi läser in definitionerna
xclock*analog: True xclock*hands: Green XClock*update: 1 digitalur*analog: False digitalur*font: -*-courier-bold-r-*--18-*-75-75-m-*-iso8859-1med xrdb och sedan ger kommandot xclock -name digitalur &, så får vi alltså en digital klocka som uppdateras varje sekund.
Man kan ta reda på klassnamn och klientnamn för ett visst fönster genom att ge kommandot xprop och sedan klicka på fönstret. Då spottas en sida text ut. Texten ger information om fönstret, bla en rad i stil med
WM_CLASS(STRING) = "digitalur", "XClock"Detta betyder att klientnamnet var digitalur och klassnamnet XClock.
Övning. Ändra rotfönstrets färg till något som passar dig.
Övning.
Starta en xclock med kommandot xclock -update 1
(utan något avslutande &-tecken).
Tryck C-c efter en liten stund. Vad händer?
Starta en ny xclock med samma kommando.
Tryck C-z. Vad händer? Starta om klockan
i bakgrunden.
Övning. Välj en ny pekare för rotfönstret.
Övning. Starta en xcalc av storleken 200x300 punkter en liten bit från bildskärmens nedre vänstra hörn.
Övning. Starta en xcalc med andra för- och bakgrundsfärger än svart och vitt.
Övning.
Starta en xterm som använder fonten
-b&h-lucidatypewriter-medium-r-*-sans-18-*-100-100-*-*-iso8859-1.
Övning. Välj en font med hjälp av xfontsel. Starta en xterm med den fonten.
Övning. Starta en digital xclock som använder någon ''proportionell'' font (dvs där tecknen inte behöver vara lika breda).
Övning. Hur går det om man startar en xterm med en proportionell font?
Övning. Skapa en fil som definierar några resursvärden för xclock, läs in filen med xrdb och starta sedan en xclock.
Övning. Lägg in några resursvärden för xclock i din .Xresources, gå ur X och starta X igen. Starta sedan en xclock.
Övning. Sätt värdet av resursen Emacs.geometry till önskad storlek för Emacs-fönstret, tex 60x30. Starta sedan Emacs.
Övning. Ta reda på klientnamnet för Emacs med hjälp av xprop.
Övning. Logga in på en annan dator. Starta programmet xclock där - men se till att bilden hamnar på den skärm du sitter vid.
Med hjälp av kommandot grep kan man söka
efter text i en fil.
Syntaxen är grep mönster filnamn.
Varje rad i filen filnamn som innehåller
texten mönster skrivs ut.$ grep den bellman
när döden ropar: Granne, kom,
den skönsta nymf, som åt dig ler,
$Kommandot ger ingen utskrift ifall mönstret inte påträffades:$ grep Linux bellman
$Man får ange flera filer att söka i.$ grep ull bellman lenngren
bellman:från Bacchi buller och tumult,
bellman: ditt timglas är nu fullt.
lenngren:hans runda armar hull och märg,
lenngren:och magen, kullrig som ett berg,
$Om man inte anger något
filnamn, så söker grep
i stället efter mönstret i sin indata.$ cat bellman lenngren | grep ost
Vår prost jag häromdagen såg
sin frukost redan färdig fann
$För de flesta ändamål klarar man sig med denna kunskap om grep.
Många läsare kan alltså hoppa över resten av detta avsnitt,
som ger en utförlig beskrivning av hur grep
kan göra avancerade sökningar.
Vi ska först beskriva några av de flaggor man kan ge grep.
Sedan ska vi studera så kallade reguljära mönster
som kan hjälpa oss att ge en mycket precis beskrivning
av den text vi söker efter.
Om man anropar grep med flaggan -v, så skrivs
de rader som inte gav träff ut.$ grep -v e bellman
Så lunka vi så småningom
ditt timglas är nu fullt.
och du, du yngling, lyd min lag:
$Tydligen finns det
bara tre rader i filen bellman som saknar bokstaven ''e''.
Flaggan -i betyder att grep inte ska skilja
mellan stora och små bokstäver:$ grep -i gra bellman
när döden ropar: Granne, kom,
Tycker du, att graven är för djup,
$Flaggan -n får grep att numrera raderna:$ grep -n du bellman
6:och du, du yngling, lyd min lag:
9:Tycker du, att graven är för djup,
12: så dör du nöjdare.
$Flaggan -i, där i är ett heltal,
innebär att grep också ska skriva
ut de i rader som kommer före respektive efter den rad som
matchar mönstret. $ grep -1 glas bellman
när döden ropar: Granne, kom,
ditt timglas är nu fullt.
Du gubbe, fäll din krycka ner,
$När man söker i flera filer, skriver grep i början
av varje rad ut vilken fil raden kommer från. För att slippa
detta ska man ge flaggan -h:$ grep -h ull bellman lenngren
från Bacchi buller och tumult,
ditt timglas är nu fullt.
hans runda armar hull och märg,
och magen, kullrig som ett berg,
$Om man enbart vill veta vilka filer som innehåller
mönstret, så ska man ge flaggan -l.$ grep -l ull bellman lenngren
bellman
lenngren
$Texten ''glas'' förekommer bara i filen bellman:$ grep -l glas bellman lenngren
bellman
$Flaggan -L ger oss i stället de filer som inte
innehåller mönstret:$ grep -L glas bellman lenngren
lenngren
$För att få veta antalet träffar ska vi ge flaggan -c:$ grep -c ull bellman lenngren
bellman:2
lenngren:2
$Flaggan -q undertrycker all utskrift från grep:$ grep -q vi bellman
lenngren
$
Med hjälp av find kan man spåra upp filer som har vissa specificerade egenskaper, tex att deras namn ser ut på ett visst sätt, att de har en viss storlek, har ändrats inom en viss tidsperiod osv. Det enklaste sättet att använda find är
På detta kommando söker find i katalogen katalog, inklusive dess underkataloger, efter filer vars namn matchar mönster. Mönstret får innehålla jokertecken precis som i skalet. Eventuella jokertecknen ska dock inte tolkas av skalet utan av find, så man måste ofta skydda mönstret.findkatalog-namemönster
Så här söker vi i katalogen /usr
efter filer vars namn innehåller ordet ''quake'':$ find /usr -name '*quake*'
/usr/doc/quake-lib
/usr/doc/xquake
/usr/games/xquake.real
/usr/games/xquake
/usr/lib/menu/xquake
/usr/share/gnome/apps/Games/Arcade/Xquake.desktop
/usr/share/games/quake
$Om argumentet katalog är rotkatalogen /,
så söker find bland samtliga filer i datorn.
Om katalog utelämnas, så antar
find att man syftar på den nuvarande katalogen.$ find -name 'bell*'
./bellman
./dikter/bellman
$
Genom att kombinera find och grep man söka efter filer som innehåller en viss text. Syntaxen för detta är
findkommando | xargs grepkommando
Filnamnen tas fram av find och skickas
med hjälp av programmet xargs
till grep, som i sin tur
söker efter texten i filerna.$ find -name '*n' | xargs grep ost
Det korrekta sättet att använda disketter är att först montera dem. Hur det går till beskriver vi i avsnitt 7.4. På många system tillåts det inte att användarna på egen hand monterar disketter; i sådana fall tvingas de att använda något som kallas för Mtools. Mtools är en samling kommandon med vars hjälp man kan läsa från, och skriva till, disketter av ''DOS-format''. Detta är det ursprungliga formatet från IBM:s första PC-datorer. Det finns en mängd märkliga restriktioner i samband med DOS-formatet. Bland annat får filnamnen inte se ut hur som helst, och filskyddskoderna bevaras inte. Därför brukar man bara använda DOS-disketter om det finns tvingande skäl, som tex att man inte har rättighet att montera disketter eller att man måste flytta filer till eller från någon dator som inte kör Linux.
I de kommandon som ingår i Mtools kallas den första
diskettenheten för a:, den andra för
b: osv.
Kommandot mdir listar filerna på disketten:$ mdir a:
Volume in drive A has no label
Volume Serial Number is 6E8A-0F0B
Directory for A:/
gnulinux dvi 61948 03-01-1998 18:11 gnulinux.dvi
1 file(s) 61 948 bytes
1 395 712 bytes free
$Bara en fil, gnulinux.dvi finns på disketten.
Med hjälp av mcopy kopierar vi filen bellman
till disketten:$ mcopy bellman a:
Copying bellman
$ mdir a:
Volume in drive A has no label
Volume Serial Number is 6E8A-0F0B
Directory for A:/
gnulinux dvi 61948 03-01-1998 18:11 gnulinux.dvi
bellman 372 03-01-1998 18:11 bellman
2 file(s) 62 320 bytes
1 395 200 bytes free
$Vi kan också kopiera filer från disketten till
datorn med mcopy. Om man inte anger någon destinationskatalog,
så placeras kopian i den nuvarande katalogen.$ mcopy a:gnulinux.dvi
Copying gnulinux.dvi
$ ls
bellman dikter/ gnulinux.dvi lenngren
$
Kommandot mdel raderar filer på disketten:$ mdel a:gnulinux.dvi
Removing gnulinux.dvi
$ mdir a:
Volume in drive A has no label
Volume Serial Number is 6E8A-0F0B
Directory for A:/
bellman 372 03-01-1998 18:11 bellman
1 file(s) 372 bytes
1 457 152 bytes free
$
Man får använda jokertecken:$ mdel a:*
Removing bellman
$ mdir a:
Volume in drive A has no label
Volume Serial Number is 6E8A-0F0B
Directory for A:/
File "*" not found
1 457 664 bytes free
$Man bör skydda jokertecknen som gäller filer på disketten
från skalet, för det är Mtools som ska tolka dem.
Anledningen till att jag struntade i att sätta apostrofer
kring a:* ovan är att jag visste att det inte fanns
någon fil i den nuvarande katalogen vars namn började med tecknen
a:.
Kommandot mlabel kan sätta ett slags namn på disketten:$ mlabel a:dikter
$ mdir
Volume in drive A is DIKTER
Volume Serial Number is 6E8A-0F0B
Directory for A:/
File "*" not found
1 457 664 bytes free
$
Disketter har högst begränsad kapacitet.
Om man vill spara en mycket stor fil på diskett,
så måste filen delas upp i bitar som ryms på var sin diskett.
Vi ska nu visa hur det går till.
(Ett annat sätt är att använda tar med flaggan -M,
se avsnitt 5.4.)
Antag att
det finns en stor fil med namnet gnulinux.ps i katalogen
/tmp:$ ls -l /tmp/gnulinux.ps
-rw-r--r-- 1 göran göran 2548527 mar 1 11:01 /tmp/gnulinux.ps
$Vi styckar upp filen i småbitar med kommandot split.
Småbitarna sparas i filer med namnen xaa, xab,
xac osv i den nuvarande katalogen.$ split -b 1400k /tmp/gnulinux.ps
$ ls -l
total 2567
-rw------- 1 göran göran 372 feb 1 16:48 bellman
drwxrwxr-x 3 göran göran 1024 feb 20 13:19 dikter/
-rw-rw-r-- 1 göran göran 61948 mar 1 18:12 gnulinux.dvi
-rw-rw-r-- 1 göran göran 649 feb 1 15:53 lenngren
-rw-rw-r-- 1 göran göran 1433600 mar 1 19:50 xaa
-rw-rw-r-- 1 göran göran 1114927 mar 1 19:50 xab
$Flaggan -b betyder att nästa argument anger den maximala
storleken för småbitarna. Vi valde storleken 1400 kilobyte.
Bokstaven ''k'' efter siffran 1400 i instruktionen ovan
står för kilobyte. I stället för ''k'' kan man ange ''b'',
som står för block (ett block är en halv kilobyte)
eller ''m'', som står för megabyte. Om bokstaven utelämnas,
så antas siffran ange antal byte.
Filerna xaa och xab kan nu kopieras till diskett.
När de kopierats över till en dator igen kan de sättas samman
med hjälp av cat på följande sätt:$ cat xa? > gnulinux.ps
$ ls -l gnulinux.ps
-rw-rw-r-- 1 göran göran 2548527 mar 1 20:12 gnulinux.ps
$ rm gnu* xa?
$
På UNIX-system motsvaras varje hårdvaruenhet av en
fil i katalogen /dev.
Den första diskettstationen motsvaras av filen
/dev/fd0, den andra av /dev/fd1 osv.$ ls -l /dev/fd0
brw-rw---- 1 root floppy 2, 0 maj 28 02:49 fd0
$Som synes av filrättigheterna
måste man be systemadministratören om
att få bli medlem av gruppen floppy innan man
kan använda diskettenheten.
Disketter måste formatteras innan de kan användas. Formatteringen sker i två steg. Det första steget, lågnivåformatteringen, består i att det lagringsutrymme som finns på disketten struktureras och delas in i spår och sektorer. Det vanliga är att disketter formatteras med 18 spår à 80 sektorer på vardera sidan. Sammanlagt blir det 2880 sektorer. En sektor innehåller 512 byte (en halv kilobyte), så lagringsutrymmet blir det välkända 1440K. (Man kan genom att använda fler spår, fler sektorer på varje spår och större sektorer få in mer på en vanlig diskett, upp till 1992K, men detta rekommenderas inte - bland annat eftersom det oftare blir fel vid avläsningen då.) Kommandot superformat /dev/fd0 formatterar en diskett i första diskettstationen. Om någon sektor är dålig, så får man veta detta; i så fall bör disketten kasseras. Lågnivåformatteringen tar ganska lång tid, men den behöver bara göras en gång för varje diskett.
Efter lågnivåformatteringen måste man skapa ett filsystem
på disketten innan den kan användas;
detta är det andra steget i formatteringsprocessen.
(Om man använder tar eller dd för att
läsa från eller skriva till disketten behövs dock
inget filsystem.)
Vanligtvis använder man endera av minix
eller ext2 som filsystem.
Ett mindre bra alternativ är filsystemet
msdos eller vfat, som används för
DOS-disketter.
Så här gör man för att formattera disketten:$ superformat /dev/fd0
Verifying track 79, head 1
mformat -s18 -t80 -h2 -S2 -M512 a:
$Kommandot superformat lägger automatiskt ett filsystem
av typen msdos på disketten.
Så här kan vi skapa ett filsystem av typen ext2:$ /sbin/mkfs -t ext2 /dev/fd0
mke2fs 1.10, 24-Apr-97 for EXT2 FS 0.5b, 95/08/09
Linux ext2 filesystem format
Filesystem label=
360 inodes, 1440 blocks
72 blocks (5.00%) reserved for the super user
First data block=1
Block size=1024 (log=0)
Fragment size=1024 (log=0)
1 block group
8192 blocks per group, 8192 fragments per group
360 inodes per group
Writing inode tables: done
Writing superblocks and filesystem accounting information: done
$Nu är disketten klar att användas.
För att UNIX ska kunna skriva till eller läsa från en
diskett med de vanliga kommandona
cp, ls osv, måste den dock först monteras, se
avsnitt 7.4.
Om vi vill byta till ett minix-filsystem, så gör vi så här:$ /sbin/mkfs -t minix /dev/fd0
480 inodes
1440 blocks
Firstdatazone=19 (19)
Zonesize=1024
Maxsize=268966912
$Observera att det inte är nödvändigt att lågnivåformattera
disketten igen!
För att byta till ett msdos-filsystem är det enklast att använda
mformat:$ mformat a:
$
Med hjälp av programmet tar kan man slå samman flera filer eller tom katalogstrukturer till en enda fil, en så kallad arkivfil. Poängen med detta är framförallt att det blir lättare att flytta filerna någon annanstans, till exempel via nätet. Ett annat skäl att använda tar kan vara att man vill lagra filerna som en säkerhetskopia. Faktum är att ''tar'' kommer från tape archive, bandarkiv, eftersom det ursprungligen användes för säkerhetskopiering av filer till magnetband.
Genom att ge argumentet -cvf dikter.tar
följt av namnen på de filer som ska ingå i arkivet,
skapar man ett arkiv med namnet dikter.tar.$ ls
bellman dikter/ lenngren
$ tar -cvf dikter.tar bellman lenngren
bellman
lenngren
$ ls
bellman dikter/ dikter.tar lenngren
$Flaggan -c står för ''skapa arkiv'' och
-v för ''skriv ut information''.
Argumentet -f namn talar om att
arkivfilen ska heta namn.
Vanligtvis brukar man ge arkivfiler namn med ändelsen
.tar, men detta är inget krav.
För att titta i en arkivfil använder man flaggan
-t i stället för -c.$ tar -tvf dikter.tar
-rw------- göran/göran 372 1998-02-01 16:48 bellman
-rw-rw-r-- göran/göran 649 1998-02-01 15:53 lenngren
$Så nu kan vi skicka iväg filen dikter.tar
och sedan packa upp den för att få en kopia av
de båda filerna bellman och lenngren.
Man packar upp ett arkiv genom att använda flaggan -x
i stället för -c.
Låt oss demonstera det hela genom att radera de ursprungliga
filerna för att sedan återställa dem från arkivfilen:$ rm bellman lenngren
$ tar -xvf dikter.tar
bellman
lenngren
$ ls -l
total 13
-rw------- 1 göran göran 372 feb 1 16:48 bellman
drwxrwxr-x 3 göran göran 1024 feb 20 13:19 dikter/
-rw-rw-r-- 1 göran göran 10240 mar 1 22:47 dikter.tar
-rw-rw-r-- 1 göran göran 649 feb 1 15:53 lenngren
$
Ofta komprimerar man arkivfilerna med gzip
för att de inte ska ta så mycket utrymme. Detta steg kan
tar göra automatiskt om man anger flaggan -z.
Komprimerade arkiv brukar ha namn med ändelsen
.tar.gz eller .tgz.
Låt oss göra ett komprimerat arkiv av hela katalogen
dikter:$ tar -zcvf dikter.tgz dikter
dikter/
dikter/bellman
dikter/lenngren
$Filen dikter.tgz är nu ett komprimerat arkiv som
innehåller katalogen dikter och alla dess filer.
Låt oss kontrollera att detta är korrekt:$ tar -ztvf dikter.tgz
drwxrwxr-x göran/göran 0 1998-02-27 19:43 dikter/
-rw------- göran/göran 372 1998-02-01 17:12 dikter/bellman
-rw-rw-r-- göran/göran 649 1998-02-01 17:12 dikter/lenngren
$Källkoden till stora program består ofta av åtskilliga filer, och
distribueras därför vanligtvis i form av komprimerade arkiv.
Om man vill spara arkivfilen på diskett, så ska man
ange tex /dev/fd0 som arkivfil
(se avsnitt 5.3).
Allt som tidigare var lagrat på disketten försvinner i
så fall.
Kommandot tar -Mcvf /dev/fd0 ~ gör en säkerhetskopia av
hela den egna hemkatalogen.
Eventuellt kan det behövas mer än en diskett,
men tack vare flaggan -M tillåter tar
att arkivet består av flera ''volymer''. De enskilda volymerna kan
vara disketter eller magnetband. När en volym är full
stannar tar upp och uppmanar användaren att sätta i en ny.$ tar -Mcvf /dev/fd0 /tmp
tar: Tar bort inledande "/" från absoluta sökvägar i arkivet
tmp/
tmp/gnulinux.ps
Gör iordning volym nummer 2 för /dev/fd0 och tryck vagnretur:
$För att packa upp arkivet ska man sätta första volymen i
diskettenheten och därefter ge kommandot
tar -Mxvf /dev/fd0. Meddelanden skrivs ut av
tar när det är dags att byta volym.
I avsnitt 3.2 beskrev vi det gränssnitt till jobbkontroll som Bash erbjuder. I detta avsnitt ska vi ta upp fler sätt att kontrollera och manipulera processer.
Med hjälp av kommandot ps kan man kontrollera
vilka processer som är igång på datorn.$ ps
PID TTY STAT TIME COMMAND
5596 p0 S 0:00 -bash
5599 p2 S 0:01 /usr/bin/xdvi.bin -name xdvi gnulinux.dvi
5639 p2 S 0:00 gs -sDEVICE=x11 -dNOPAUSE -dSAFER -q -
5668 p0 R 0:00 ps
$ Status för en process (rubriken STAT ovan) kan vara
R (Running; igång),
S (Sleeping; sysslolös) och
T (Stopped; stoppad, eller snarare pausad).
Instruktionen som startade respektive process anges
i sista fältet av varje rad ovan. Det näst sista fältet
visar hur mycket av datorns tid instruktionen tagit i
anspråk.
Varje process har ett nummer, dess processidentifikationsnummer (PID), med vars hjälp man referar till processen. De flesta processer har en kontrollterminal, nämligen den terminal processen startades från. Eventuell indata till kommandot läses in från kontrollterminalen, och utdata skrivs ut där. Det andra fältet (under rubriken TTY) ovan anger processens kontrollterminal.
Varje terminal motsvaras av en fil i katalogen /dev. De virtuella terminalerna, som man kommer till genom samtidigt att trycka Ctrl, Alt och en av funktionstangenterna F1 till F6, har filnamn tty1 till tty6, medan pseudoterminaler har filnamn ttyp1, ttyp2 osv. Kommandot ps från sista raden ovan körs i pseudoterminalen /dev/ttyp0.
Flaggorna till ps anges på ett något
annorlunda sätt än vanligt
(detta kommer att ändras i en kommande utgåva av programmet).
Om man ger flaggan u, så skrivs utförligare
information ut.$ ps u
USER PID %CPU %MEM SIZE RSS TTY STAT START TIME COMMAND
göran 5596 0.0 1.9 1832 1228 p0 S 08:32 0:00 -bash
göran 5599 0.0 3.4 3160 2184 p2 S 08:33 0:01 /usr/bin/xdvi.bi
göran 5639 0.0 3.9 4540 2528 p2 S 10:07 0:00 gs -sDEVICE=x11
göran 5670 0.0 0.8 908 540 p0 R 10:39 0:00 ps u
$ Här ser vi också vem som startade processen (USER),
när den startades (START),
hur många procent av datorns tid (%CPU)
respektive minne (%MEM) processen förbrukar,
hur stor processen är (SIZE, i kilobyte) samt
hur mycket av den som finns i minnet just nu
(RSS).
Bara de processer man själv startat listas ovan.
Använd flaggan a om också alla andras
processer ska tas med.
De processer som inte har någon kontrollterminal
finns inte heller med ovan, utan man måste ge ps
flaggan x
för att få information om dem.$ ps x
PID TTY STAT TIME COMMAND
5580 ? S 0:01 /usr/X11R6/bin/fvwm2
5592 ? S 0:00 /usr/X11R6/lib/X11/fvwm2/FvwmPager 9
5594 ? S 0:00 /usr/X11R6/lib/X11/fvwm2/FvwmButtons
5595 ? S 0:00 xclock -update 1 -padding 4 -bg Dark
5596 p0 S 0:00 -bash
5598 ? S 0:58 /usr/bin/xemacs
5599 p2 S 0:01 /usr/bin/xdvi.bin -name xdvi gnulinu
5639 p2 S 0:00 gs -sDEVICE=x11 -dNOPAUSE -dSAFER -q
5672 p0 R 0:00 ps x
$ De processer som saknar kontrollterminal har ett frågetecken
under rubriken TTY. I utskriften ovan finns fem sådana
processer; de utgörs av fönsterhanteraren och program
som startats genom den.
Kommandot top ger ungefär samma information som ps. Men top sorterar processerna efter hur mycket processortid de använder, och informationen uppdateras med jämna intervall tills man trycker q. Man skulle kunna säga att top är en ''live-version'' av ps. Det finns åtskilliga X-program som ger motsvarande information, tex Gtop, se figur 5.1.
Här är ett exempel på utdata från programmet top:
10:53am up 16 days, 22:07, 3 users, load average: 0.00, 0.00, 0.10
41 processes: 40 sleeping, 1 running, 0 zombie, 0 stopped
CPU states: 3.7% user, 0.9% system, 0.0% nice, 95.4% idle
Mem: 63356K av, 61184K used, 2172K free, 26664K shrd, 9376K buff
Swap: 96352K av, 316K used, 96036K free 23856K cached
PID USER PRI NI SIZE RSS SHARE STAT LIB %CPU %MEM TIME COMMAND
5675 göran 19 0 772 772 592 R 0 3.7 1.2 0:00 top
15350 root 8 0 5268 5260 1596 S 0 0.9 8.3 61:42 XF86_Mach64
1 root 0 0 232 216 160 S 0 0.0 0.3 0:01 init
2 root 0 0 0 0 0 SW 0 0.0 0.0 0:00 kflushd
3 root -12 -12 0 0 0 SW< 0 0.0 0.0 0:00 kswapd
4 root 0 0 0 0 0 SW 0 0.0 0.0 0:00 nfsiod
5 root 0 0 0 0 0 SW 0 0.0 0.0 0:00 nfsiod
6 root 0 0 0 0 0 SW 0 0.0 0.0 0:00 nfsiod
7 root 0 0 0 0 0 SW 0 0.0 0.0 0:00 nfsiod
15326 root 0 0 972 972 656 S 0 0.0 1.5 0:00 bash
15324 root 0 0 312 312 232 S 0 0.0 0.4 0:00 getty
119 root 0 0 580 548 452 S 0 0.0 0.8 0:05 sshd
14 root 0 0 92 64 52 S 0 0.0 0.1 0:07 update
85 root 0 0 372 364 272 S 0 0.0 0.5 0:00 syslogd
87 root 0 0 360 352 180 S 0 0.0 0.5 0:00 klogd
96 root 0 0 204 196 148 S 0 0.0 0.3 0:00 kerneld
100 daemon 0 0 344 340 268 S 0 0.0 0.5 0:00 portmap
102 root 0 0 376 368 300 S 0 0.0 0.5 0:00 inetd
152 root 0 0 304 284 224 S 0 0.0 0.4 0:00 getty
126 root 0 0 760 748 356 S 0 0.0 1.1 22:00 rpc.nfsd
128 root 0 0 568 556 444 S 0 0.0 0.8 0:00 rpc.mountd
132 nobody 0 0 272 264 204 S 0 0.0 0.4 0:00 dhttpd
135 daemon 0 0 308 276 220 S 0 0.0 0.4 0:00 atd
138 root 0 0 348 340 256 S 0 0.0 0.5 0:00 cron
30196 root 0 0 1544 1544 1204 S 0 0.0 2.4 0:00 xdm
153 root 0 0 296 296 216 S 0 0.0 0.4 0:00 getty
15348 root 0 0 684 672 572 S 0 0.0 1.0 0:00 xdm
5580 göran 1 0 1284 1284 896 S 0 0.0 2.0 0:01 fvwm2
5590 root 0 0 2104 2104 1448 S 0 0.0 3.3 0:01 xterm
30205 root 0 0 1436 1436 1196 S 0 0.0 2.2 0:00 xconsole.real
5592 göran 0 0 720 720 620 S 0 0.0 1.1 0:00 FvwmPager
5595 göran 0 0 1260 1260 1052 S 0 0.0 1.9 0:00 xclock
5594 göran 0 0 808 808 696 S 0 0.0 1.2 0:00 FvwmButtons
5596 göran 15 0 1228 1228 884 S 0 0.0 1.9 0:00 bash
30150 root 0 0 1456 1436 700 S 0 0.0 2.2 2:29 sshd
5599 göran 0 0 2184 2184 1328 S 0 0.0 3.4 0:01 xdvi.bin.real
5598 göran 0 0 7464 7464 3056 S 0 0.0 11.7 1:01 xemacs
5639 göran 0 0 2528 2528 1736 S 0 0.0 3.9 0:00 gs
30152 eva 0 0 1176 1176 860 S 0 0.0 1.8 0:00 bash
30154 eva 0 0 9544 9540 1876 S 0 0.0 15.0 0:48 gimp
30155 eva 0 0 1996 1980 708 S 0 0.0 3.1 0:00 script-fu
Man kan ''kommunicera'' med en process genom att skicka signaler till den med hjälp av kommandot kill. Ofta används kill till att avsluta processer, men kommandot kan också ha andra, mindre destruktiva effekter - tex att processen tar en paus eller att den startar om. Bara root och ägaren av en process får skicka signaler till den.
Signaler har såväl namn som nummer. Man kan referera till en signal antingen med dess namn, som tex SIGCONT (eller kortare CONT), eller dess nummer, som 18. Några viktiga signaler ges i tabell 5.2.
Processer kan förbereda sig för att ta emot olika signaler, och ha en åtgärd redo ifall en viss signal skulle komma. Man säger då att processen fångar signalen. Åtgärden kan vara att helt enkelt strunta i signalen, eller tex att spara alla data, skriva ett felmeddelande och avsluta. Om signalen inte fångas, så vidtas en standardåtgärd på processen. Två av signalerna, SIGKILL och SIGSTOP, kan aldrig fångas.
|
Vi minns att man kan pausa ett förgrundsjobb
i Bash genom att trycka C-z.
Mer allmänt kan man pausa en process
genom att skicka signalen
SIGSTOP till den.
För att låta processen fortsätta kan man
vid ett senare tillfälle skicka signalen
SIGCONT till den.$ gzip -9 /tmp/gnulinux.ps &
[1] 5682
$ ps 5682
PID TTY STAT TIME COMMAND
5682 p0 R 0:04 gzip -9 /tmp/gnulinux.ps
$ kill -STOP 5682
$ ps 5682
PID TTY STAT TIME COMMAND
5682 p0 T 0:14 gzip -9 /tmp/gnulinux.ps
[1]+ Stopped gzip -9 /tmp/gnulinux.ps
$ kill -CONT 5682
$ ps 5682
PID TTY STAT TIME COMMAND
5682 p0 R 0:21 gzip -9 /tmp/gnulinux.ps
$ ls /tmp
gnulinux.ps.gz
[1]+ Done gzip -9 /tmp/gnulinux.ps
$ Ovan körs först en tung process igång.
Med hjälp av ps ser vi att processen kör för fullt.
Kommandot kill -STOP 5682 skickar
signalen SIGSTOP till processen,
och en kontroll visar att den faktiskt är pausad
(dess status är T). Efter en stund skickas signalen
SIGCONT till processen, och då fortsätter den
därifrån den stannade. Dess status är återigen R.
Senare, efter kommandot ls /tmp,
ser vi att processen kört färdigt.
Kommandot kill vill som flagga
ha namn eller nummer på en signal att skicka.
Om flaggan utelämnas, så skickas signalen
SIGTERM. Argumenten består av
ett eller flera processidentifikationsnummer,
som anger vilken eller vilka processer signalen
ska skickas till.
Om kill anropas med flaggan -l,
så ges en lista över alla signaler.$ kill -l
1) SIGHUP 2) SIGINT 3) SIGQUIT 4) SIGILL
5) SIGTRAP 6) SIGABRT 7) SIGBUS 8) SIGFPE
9) SIGKILL 10) SIGUSR1 11) SIGSEGV 12) SIGUSR2
13) SIGPIPE 14) SIGALRM 15) SIGTERM 17) SIGCHLD
18) SIGCONT 19) SIGSTOP 20) SIGTSTP 21) SIGTTIN
22) SIGTTOU 23) SIGURG 24) SIGXCPU 25) SIGXFSZ
26) SIGVTALRM 27) SIGPROF 28) SIGWINCH 29) SIGIO
30) SIGPWR
$
Signalen SIGTERM är en önskan om att processen ska avsluta. Vissa processer fångar denna signal och struntar i den. Andra processer fångar signalen, sparar sina data och städar upp efter sig innan de avslutar. Slutligen finns det processer som inte fångar signalen SIGTERM, och då vidtas standardåtgärden som är att avsluta dem. Om man vill ta bort en process som inte ger med sig på något annat sätt, så kan man skicka SIGKILL till den. Då avslutas processen utan att den först ''tillfrågas''. Detta kan ha obehagliga effekter - om man tex skickar SIGKILL till Emacs, så förlorar man alla ändringar som inte är sparade. Det är alltså bäst att prova SIGTERM först; bara om detta inte hjälper ska man använda SIGKILL.
Antag att vi har följande processer igång:$ ps
PID TTY STAT TIME COMMAND
1485 p1 S 0:00 -bash
1491 p2 S 0:00 -bash
1502 p3 S 0:00 xdvi.bin -name xdvi oh.dvi
1549 p2 R 54:05 dedekind 1232112423
1598 p1 R 0:00 ps
$Vi försöker nu ta bort process 1491, ett Bash-skal:$ kill 1491
$ ps 1491
PID TTY STAT TIME COMMAND
1491 p2 S 0:00 -bash
$Kontrollen med ps visar att Bash-skalet finns kvar.
Detta beror på att Bash fångar signalen SIGTERM
och struntar i den. Vi måste då ta till SIGKILL:$ kill -9 1491
$ ps 1491
PID TTY STAT TIME COMMAND
No processes available.
$Utskriften från ps visar att processen är borttagen.
Process 1549 (som körde under det skal vi nyss tog bort
och som nu saknar kontrollterminal)
kan vi däremot ta bort med SIGTERM:$ ps 1549
PID TTY STAT TIME COMMAND
1549 ? R 62:33 dedekind 1232112423
$ kill 1549
$ ps 1549
PID TTY STAT TIME COMMAND
No processes available.
$
När man i skalet trycker C-c skickas signalen SIGINT till de processer som är i förgrunden. Detta får vanligtvis processerna att avsluta.
Signalen SIGHUP betyder att processen
är ''avringd'', vilket tex kan innebära
att man loggat ut. Vissa processer struntar i
denna signal, andra avlutar och åter andra
läser in sina konfigurationsfiler och startar om.
Om man vill att en process ska ligga kvar även efter
att man loggat ut, så måste man i vissa fall skydda
den mot signalen SIGHUP. Detta gör man genom
att starta den med nohup kommando &
Om ett program ''utför en förbjuden åtgärd'', så skickas signalen SIGSEGV till den. Nästan alltid får detta till följd att programmet avslutar och gör en minnesutskrift i en fil med namnet core. Minnesutskriften är till för att programutvecklare ska kunna ta reda på vad som vållade felet.
Kommandot killall är en variant av kill.
Skillnaden mellan dessa kommandon
ligger i hur man anger vilka processer signalen ska
skickas till.
I fallet kill anges processernas PID,
men till killall anges i stället
det kommando som startade processerna.
En fördel med killall är att vi slipper ta reda
på PID för processerna ifråga.$ xfontsel &
[1] 5874
$ killall xfontsel
[1]+ Avslutad xfontsel
$
Om en process startar en ny process, så är den nya processen
barn till den gamla, och den gamla processen är
förälder till den nya.
Förälderns PID kallas för processens PPID.
Kommandot pstree ritar ut processernas
släktträd med utgångspunkt från urmodern init
(som har PID 1)
eller, om man vill, från en given process.$ ps x
PID TTY STAT TIME COMMAND
5580 ? S 0:04 /usr/X11R6/bin/fvwm2
5592 ? S 0:00 /usr/X11R6/lib/X11/fvwm2/FvwmPager 9
5594 ? S 0:00 /usr/X11R6/lib/X11/fvwm2/FvwmButtons
5596 p0 S 0:00 -bash
5598 ? S 1:48 /usr/bin/xemacs
5599 p2 S 0:02 /usr/bin/xdvi.bin -name xdvi gnulinu
5639 p2 S 0:00 gs -sDEVICE=x11 -dNOPAUSE -dSAFER -q
5868 ? S 0:00 xclock -update 1 -padding 4 -bg Dark
5876 p0 R 0:00 ps x
$ pstree 5580
fvwm2-+-FvwmButtons
|-FvwmPager
|-xclock
`-xterm---bash---pstree
$
Varje process har ett snällhetsvärde som bestämmer hur stor del av processorns tid processen får. Värdet är ett heltal mellan -20 och 19. Ju högre värdet är, desto snällare är processen i den meningen att den kräver mindre av processorkraften. Vanligtvis ärver en process snällhetsvärdet från sin förälder; standardvärdet är 0. Det är bara root som får sänka snällhetsvärdet för en process. Däremot kan vanliga användare höja det för sina processer med kommandot nice. Om en process startas med nice kommando, så ges den ett snällhetsvärde som är 10 enheter större än dess förälder (men högst 19). Om den ska ha tex värdet 5 högre än föräldern, ska den startas med instruktionen nice -n 5 kommando. Om man ger denna instruktion i ett skal med snällhetsvärde 10, så körs alltså kommando med snällhetsvärde 15. Snällhetsvärdet skrivs ut under rubriken ''NI'' i top, se tabell 5.1.
Om en process redan är igång, så kan man ändra dess
snällhetsvärde med kommandot renice.
Nedan startar vi en process och sätter sedan dess snällhetsvärde
till 3.$ xfontsel &
[1] 5935
$ renice +3 5935
5935: old priority 0, new priority 3
$Vi ändrar snällhetsvärdet till 7:$ renice +7 5935
5935: old priority 3, new priority 7
$Man får inte sänka värdet, utan bara höja det.$ renice +5 5935
renice: 5935: setpriority: Åtkomst nekas
$
Man kan använda variabler i Bash. En variabel är ett namn som har getts ett visst värde. Variabelnamnet får bara innehålla bokstäverna a till z samt siffror och understrykningstecken, och det får inte börja med en siffra. Värdet är helt enkelt en följd av tecken; det finns inga datatyper som tex heltal eller flyttal.
Kommandot namn=värde
ger variabeln namn värdet värde.
(Det får inte finnas något mellanrum före
eller efter likhetstecknet.)
Om texten $namn
sedan förekommer
i ett kommando, så skriver Bash om kommandot genom att
byta ut $namn mot värde.
För att tilldela variabeln
ADRESS värdet goran_a@sslug.dk
ska man alltså ge kommandot$ ADRESS=goran_a@sslug.dk
$ Hädanefter vet Bash att ADRESS
har värdet goran_a@sslug.dk.
Låt oss prova att använda variabeln!$ echo $ADRESS
goran_a@sslug.dk
$Kommandot echo $ADRESS skrevs här om till
echo goran_a@sslug.dk innan det
exekverades, se figur 6.1.
Följande kommando
skickar
innehållet i filen bellman som datorpost till
adressen goran_a@sslug.dk:$ mail $ADRESS < bellman
$
Man måste komma ihåg dollartecknet
för att Bash ska sätta in variabelns värde:$ echo ADRESS
ADRESS
$Variabler kan användas inom citationstecken:$ echo "Skicka svaret till Göran <$ADRESS>"
Skicka svaret till Göran <goran_a@sslug.dk>
$Detta visar att citationstecken inte skyddar mot omskrivning
av $namn.
Om värde innehåller blank- eller nyrad-tecken,
så måste man beskydda det så att Bash
ser det som ett enda ord.$ NAMN=Göran Andersson
bash: Andersson: command not found
$ NAMN='Göran Andersson'
$ echo $NAMN
Göran Andersson
$I nästa exempel låter vi variablens värde vara
det kommando vi ska ge:$ KOMMANDO=date
$ $KOMMANDO
tis feb 17 11:05:48 CET 1998
$Man kan också lagra flaggor i en variabel:$ FLAGGOR=-l
$ echo Variabeln FLAGGOR har värdet $FLAGGOR
Variabeln FLAGGOR har värdet -l
$ ls $FLAGGOR
total 3
-rw------- 1 göran göran 372 feb 1 16:48 bellman
drwxrwxr-x 2 göran göran 1024 feb 1 17:12 dikter/
-rw-rw-r-- 1 göran göran 649 feb 1 15:53 lenngren
$Härnäst ska vi ge variabeln
NYA_FLAGGOR samma värde som
FLAGGOR men med tillägg av -t.
(Om man ger ls flaggan -t,
så sorteras filerna efter senaste ändringsdatum;
de nyaste filerna visas först.)$ NYA_FLAGGOR=$FLAGGOR -t
bash: -t: command not found
$Det blev fel eftersom vi glömde skydda blanktecknet
före -t. Vi gör ett nytt försök,
och utnyttjar då att citationstecken skyddar blanktecken men
inte dollartecken:$ NYA_FLAGGOR="$FLAGGOR -t"
$ echo $NYA_FLAGGOR
-l -t
$ ls $NYA_FLAGGOR
total 3
drwxrwxr-x 2 göran göran 1024 feb 1 17:12 dikter/
-rw------- 1 göran göran 372 feb 1 16:48 bellman
-rw-rw-r-- 1 göran göran 649 feb 1 15:53 lenngren
$ Nu ska vi ändra värdet av variabeln FLAGGOR
genom att till dess nuvarande värde lägga tecknen rt.
(Flaggan -r uppmanar ls att lista filerna i omvänd ordning.)
Men det finns ett litet problem: vi kan inte skriva
FLAGGOR=$FLAGGORrt, för då skulle FLAGGORrt
tolkas som ett variabelnamn. Men Bash tillåter att man skriver
${namn} i stället för $namn,
så vi kan göra så här:$ FLAGGOR=${FLAGGOR}rt
$ echo $FLAGGOR
-lrt
$ KOMMANDO=ls
$ $KOMMANDO $FLAGGOR
total 3
-rw-rw-r-- 1 göran göran 649 feb 1 15:53 lenngren
-rw------- 1 göran göran 372 feb 1 16:48 bellman
drwxrwxr-x 2 göran göran 1024 feb 1 17:12 dikter/
$
Det finns ett antal variabler som är av en speciell betydelse
för Bash. En sådan
variabel är PS1, vars värde bestämmer hur
prompten ser ut.$ echo $PS1
\$
$ PS1='vad nu? '
vad nu? ls
bellman dikter/ lenngren
vad nu?I värdet av PS1 kan man ange ett antal specialtecken,
se tabell 6.1.
Bla skrivs \h om till datorns namn och
\u till det egna användarnamnet.vad nu? PS1='[\u@\h \w]\$ '
[göran@fafner ~]$ cd dikter
[göran@fafner ~/dikter]$ cd /usr/doc
[göran@fafner /usr/doc]$ cd
[göran@fafner ~]$ PS1='\$ '
$I prompten ovan står tecknet ~ för min hemkatalog.
|
Värdet av variabeln PS2 bestämmer utseendet av den sekundära prompten,
den prompt man får när ett kommando sträcker sig över mer än en rad.$ echo $PS2
>
$
En annan variabel som är viktig för Bash är PATH.
Den anger en lista av kataloger, separerade av kolon,
där Bash ska leta efter program som man anropar i sina instruktioner.$ echo $PATH
/usr/local/bin:/usr/bin:/bin:/usr/bin/X11:/usr/games:.
$Till exempel använder man programmet wc i instruktionen
wc bellman.
Programmet wc är inte inbyggt i Bash,
utan det finns i filen /usr/bin/wc
på min dator.
Bash kan hitta det tack vare att katalogen
/usr/bin är uppräknad i PATH.
Så här går det om vi tar bort /usr/bin från
värdet av PATH:$ PATH=/usr/local/bin:/usr/games
$ wc bellman
bash: wc: command not found
$Vi tvingas nu ange sökvägen till wc:$ /usr/bin/wc bellman
12 71 372 bellman
$Den nuvarande katalogen . finns för tillfället
inte i värdet av PATH.
Därför måste vi ange sökvägen till
programmet wc även om vi befinner oss
i den katalog som inhyser det:$ cd /usr/bin
$ wc /home/göran/bellman
bash: wc: command not found
$ ./wc /home/göran/bellman
12 71 372 /home/göran/bellman
$Vi bör tydligen lägga tillbaka de kataloger som togs bort ur PATH:$ PATH=/usr/bin:/bin:/usr/bin/X11:$PATH:.
$ echo $PATH
$ /usr/bin:/bin:/usr/bin/X11:/usr/local/bin:/usr/games:.
$ cd
$Katalogerna i PATH genomsöks i tur och ordning.
Om det finns två olika
program med samma namn, så exekveras därför det av de båda programmen
vars ''hemkatalog'' räknas upp först i PATH.
Ordningen av katalogerna i PATH har alltså
viss betydelse.
UNIX-skal är inte bara interaktiva kommandotolkar utan även fullfjädrade programmeringsspråk. I detta avsnitt ska vi berätta hur man kan programmera i Bash.
Det är inte svårt att göra egna program i Bash.
I princip placerar man bara en följd av
Bash-kommandon i en fil.
Kommandona utförs i tur och ordning när programmet körs.
Låt oss som exempel konstruera ett program som skriver ut
texten ''Hej, världen!''.
Så här skulle man göra det från prompten:$ echo 'Hej, världen!'
Hej, världen!
$ Men nu ska vi istället skapa en
fil som innehåller detta kommando.
Filen kallar vi för hejvärlden.
I UNIX har man som konvention att
på första raden i ett sådant program
skriva tecknen #! och därefter
ange vilken tolk som ska köra det.
Filen ska alltså se ut så här
(skapa den med hjälp av Emacs och ge den namnet hejvärlden):
#!/bin/bash echo 'Hej, världen!'Nu är det dags att prova programmet. Först måste vi sätta filrättigheterna så att hejvärlden blir ett körbart program:$ ls -l hejvärlden
-rw-rw-r-- 1 göran göran 33 nov 10 00:29 hejvärlden
-rw-rw-r-- 1 göran göran 33 nov 10 00:29 hejvärlden*
Hej, världen!
/usr/bin:/bin:/usr/bin/X11:/usr/local/bin:/usr/games:.
Hej, världen!
/home/göran/bin:/usr/bin:/bin:/usr/bin/X11:/usr/local/bin:/usr/games:.
Hej, världen!
Man kan använda variabler i Bash-program, precis som vid prompten. Vi minns från avsnitt 6.1 att man måste sätta ett dollartecken framför variabelnamnet om man vill referera till variabelns värde. Vi ska nu skriva ett program som frågar efter ett namn och därefter ger en artig hälsning. Så här kan det se ut:
#!/bin/bash echo 'Ange ditt namn:' read NAMN echo "Hej, $NAMN!"Kommandot read NAMN läser in en text och sätter värdet av variabeln NAMN till denna text. På sista raden av programmet använder vi citationstecken i stället för apostrofer, för annars byter Bash inte ut $NAMN mot värdet av NAMN. Vi antar att programmet finns sparat i en exekverbar fil med namnet hej i katalogen bin. Låt oss prova:$ hej
Ange ditt namn:
Hej, Göran!
#!/bin/bash read -p 'Ange ditt namn: ' NAMN echo "Hej, $NAMN!"Därefter kör vi programmet igen:$ hej
Ange ditt namn: Göran Andersson
Hej, Göran Andersson
Man kan också låta de egna Bash-programmen läsa in argument. Det första argumentet skrivs $1, det andra $2 osv. Vi gör en ny version av programmet hej, som tar emot namnet i form av ett argument istället:
#!/bin/bash echo "Hej, $1!"Då fungerar det så här:$ nyhej Kalle
Hej, Kalle!
Hej, Nisse!
Man kan säga att 1 fungerar som en variabel i Bash, och dess värde (som man får genom att skriva $1) är det första argumentet. Det finns ett antal andra sådana så kallade parametrar i Bash. Parametrarna 2, 3... står för det andra respektive tredje argumentet osv. (För att få värdet av tex det trettonde argumentet måste man skriva ${13}. Om man skriver $13, så tolkas det som värdet av den första parametern följt av en trea.) Parametern 0 står för det nollte argumentet, som är det namn programmet anropades under. Parametern * står för samtliga argument, från det första till det sista, separerade av mellanslag, och # står för antalet argument. Här är ett exempelprogram.
#!/bin/bash
echo "Totalt $# argument."
echo "Det trettonde argumentet är ${13}."
Programmet talar först om hur många argument det fick,
och skriver sedan ut sitt trettonde argument.
Vi sparar programmet under namnet argument
i katalogen bin.$ argument 1 2 3 4 5 6 7 8 9 10 11 12 Tretton 14
Totalt 14 argument.
Det trettonde argumentet är Tretton.
Totalt 8 argument.
Det trettonde argumentet är .
Vi ändrar programmet nyhej till följande:
#!/bin/bash echo "Hej, $*!"Nu skriver programmet ut samtliga argument i stället för bara det första.$ nyhej Kalle
Hej, Kalle!
Hej, Nisse Nilsson!
Antag att vi har gett en viss variabel ett värde. Om vi sedan startar ett nytt program, känner det då till variabelns värde? Låt oss prova! Vi ger följande program namnet arv:
#!/bin/bash echo "Variabeln TEST har värdet <$TEST>."Sedan ger vi variabeln TEST värdet definierad, och kör därefter arv.$ TEST=definierad
Variabeln TEST har värdet <>.
Variabeln TEST har värdet <definierad>.
Man kan ge kommandot printenv
(eller export utan argument) för
att ta reda på vilka variabler som är exporterade:$ printenv
TEST=definierad
HOSTNAME=fafner
MANPATH=/usr/man:/usr/X11R6/man:/usr/local/man
PS1=\$
USER=göran
MACHTYPE=i486-debian-linux-gnu
LC_MESSAGES=sv_SE
LC_TIME=sv_SE
LOGNAME=göran
SHLVL=1
SHELL=/bin/bash
HOSTTYPE=i486
OSTYPE=linux-gnu
TERM=linux
HOME=/home/göran
PATH=/home/göran/bin:/usr/local/bin:/usr/bin:/bin:/usr/bin/X11:/usr/games:.
$
Men vad är det för mening med att exportera variabler?
Vi besvarar denna fråga genom att ge ett exempel.
I utskriften ovan ser vi att variabeln LC_TIME är markerad
för export. Variabeln anger vilka konventioner vi vill att
datumangivelser ska följa. Variabeln påverkar
bland andra programmet date. Det nuvarande värdet av
LC_TIME är sv_SE, som står för ''svenska i Sverige''.
Men vi ändrar nu värdet till da_DK och anropar date:$ LC_TIME=da_DK
$ date
søn feb 22 12:13:38 CET 1998
$Effekten blev att dagens datum skrevs på danskt vis
i stället för svenskt.
Vi provar nu värdet de_AT, ''tyska i Österrike'':$ LC_TIME=de_AT
$ date
Son Feb 22 12:13:52 CET 1998
$Denna gång fick vi utskriften på tyska.
Genom att exportera variabler
kan man överföra information till diverse program.
Därigenom slipper man förmedla informationen
via en massa argument varje gång programmen anropas.
Med process menas en programkörning. Om en process startar en annan process, så sägs den förra processen vara förälder till den senare, och den senare processen sägs vara barn till den förra. Om vi kör igång ett program från Bash, så är alltså Bashprocessen förälder till den nya programkörningen.
När en process startas, får den något som kallas för dess miljö. Miljön är en uppsättning variabler med definierade värden. Man skulle kunna säga att miljön är processens arvsanlag eller gener, för miljön går i arv från föräldraprocess till barnprocess. Det är inte så att det finns en enda miljö som är gemensam för alla program, utan varje process har som sagt en egen miljö som den tilldelas (ärver) av föräldern då den startas.
Vad som sker när vi exporterar en variabel i skalet är helt enkelt att variabeln placeras i miljön. Om vi sedan startar ett nytt program från Bash, så kopieras miljön till den nya programkörningen. Därför är samtliga exporterade variabler tillgängliga för de program vi startar.
Om ett Bash-skal ärver några miljövariabler från sin föräldraprocess, så gör Bash-skalet genast egna variabler som motsvarar dessa miljövariabler. Varje miljövariabel är alltså samtidigt en vanlig variabel, en så kallad skalvariabel, i Bash.
Det finns några miljövariabler, som kallas för lokaler, som används för att definiera vilket språk och vilka kulturella konventioner man vill att programmen ska hålla sig till. En av lokalerna är LC_TIME. De andra heter LC_MESSAGES, LC_COLLATE, LC_CTYPE, LC_NUMERIC och LC_MONETARY. Om man vill att datorn ska använda det svenska språket såsom det talas i Sverige, och följa svenska konventioner, så ska man sätta dessa till sv_SE. Om variabeln LC_ALL har något värde, så används detta i stället för de enskilda lokalernas värden. Om varken LC_ALL eller någon av lokalerna har något värde, så används i stället värdet av variablen LANG.
För att ta bort namn från miljön
ska man anropa export med flaggan -n:$ export -n LC_TIME
$ date
Sun Feb 22 18:29:46 CET 1998
$Efter kommandot export -n LC_TIME är variabeln
LC_TIME inte längre en del av miljön.
Därför kunde date inte se dess värde,
och vi fick utskriften på engelska.
Kommandot export namn=värde
har samma effekt som
namn=värde; export namn.$ export LC_ALL=sv_SE
$ date
sön feb 22 18:32:53 CET 1998
$
Nedan definierar vi
två variabler och markerar den ena för export.
Därefter startar vi ett nytt Bashskal i
syfte att undersöka
ifall de båda variablerna ärvs.
Det nya skalet markeras med en inramning.
Ett sådant ''skal i skalet'' kallas för ett subskal.
Det kan liknas
vid en ''berättelse i berättelsen'',
något som ofta förekommer på film.$ NAMN='Göran Andersson'
$ ADRESS=goran_a@sslug.dk
$ export ADRESS
$ bash
$ echo "Namnet är <$NAMN>"$ Over ser vi att variabeln ADRESS, som exporterats till miljön, ärvdes. Variabeln NAMN, som inte var en del av miljön, var däremot odefinierad i det nya skalet.
Namnet är <>
$ echo "Adressen är <$ADRESS>"
Adressen är <goran_a@sslug.dk>
$ exit
exit
Antag att en process, tex ett nytt Bash-skal som ovan,
har ärvt en viss variabel från föräldern genom miljön.
Antag vidare att variabeln ändras i den nya processen.
Påverkas då motsvarande variabel hos föräldern?
Nej, processen har ju sin egen miljö som är helt
fristående från förälderns miljö. Mänskliga gener
går i arv från föräldrar till barn men inte omvänt;
förälderns gener
påverkas inte ifall barnets gener senare förändras.
Detsamma gäller för olika processer och deras
miljöer, vilket följande exempel understryker:$ pwd
/home/göran
$ PS1='vad nu? '
vad nu? bash
vad nu? echo "Prompten är <$PS1>"vad nu? echo "$NAMN <$ADRESS>"
Prompten är <vad nu? >
vad nu? PS1='befall: '
befall: ADRESS=eva@turangalila.se
befall: cd /etc
befall: pwd
/etc
befall: exit
exit
\$ '
När ett Bash-skal startats vid inloggningen,
innan första prompten skrivs ut, läser Bash
in och exekverar de kommandon som finns i filen
/etc/profile om den existerar.$ cat /etc/profile
ulimit -c unlimited
umask 022
source /etc/environment
$Den första raden möjliggör för
program som ''kraschar'' att lämna
minnesutskrifter efter sig i filer med namn core
för att man ska kunna ta reda på vad som gått snett.
Den andra raden specificerar vilken filskyddskod som ska
tilldelas nya filer och kataloger.
Den sista raden använder Bash-kommandot source filnamn,
som gör att filen filnamn läses in och
exekveras. I filen /etc/environment definieras ett
antal miljövariabler:$ cat /etc/environment
PATH='/usr/local/bin:/usr/bin:/bin:/usr/bin/X11:/usr/games:.'
MANPATH='/usr/man:/usr/X11R6/man:/usr/local/man'
PS1='\u@\h \w\$ '
export PATH PS1 MANPATH
$Dessa variabeldefinitioner skulle kunna göras i
/etc/profile, men ofta är det praktiskt att på detta sätt
samla dem i en separat fil,
så att definitionerna kan användas också på andra ställen än i
Bash - tex i startfilen för fönstersystemet X.
Filen /etc/profile skapas av systemadministratören, men
exekveras för alla användare på datorn. Varje användare kan också
ha en egen startfil för Bash, .bash_profile
(om den inte existerar, så försöker Bash med
.bash_login eller .profile i stället).
Den privata startfilen körs efter den gemensamma, så varje
användare får själv sista ordet i fråga om tex värdena
på miljövariabler.$ cat .bash_profile
umask 002
export PS1='\$ '
export LC_MESSAGES=sv_SE
export LC_TIME=sv_SE
source .bashrc
$ cat .bashrc
alias ls='ls -NF --color'
$I min privata startfil för Bash ändrar jag värdena på
umask och PS1 samt sätter lokalerna
LC_MESSAGES och LC_TIME till sv_SE.
Sedan körs kommandona i filen
.bashrc - i detta fall bara ett enda kommando som ger ett
alias för ls.
(Ett lämpligt tillägg till filen är kommandot
PATH=/home/göran/bin:$PATH.)
Om man själv startar ett nytt Bash-skal med kommandot bash, så är detta inte vad Bash kallar för ett login-skal, och då exekveras inte /etc/profile och .bash_profile. Skälet till detta är att man i dessa filer främst gör grundläggande inställningar av miljövariablerna. Dels är det onödigt att köra dem igen eftersom miljön ändå ärvs av det nya skal man sstartar, och dels har man kanske ändrat några miljövariabler och vill inte att de ska ändras tillbaka. För skal som inte är login-skal körs .bashrc i stället för /etc/profile och .bash_profile. Då alias (se avsnitt 6.5) inte ärvs genom miljön kan det vara lämpligt att definiera dem i .bashrc. Ofta vill man att .bashrc ska köras också för login-skal, men då måste man själv se till att så sker genom att ha med raden source .bashrc i sin .bash_profile.
Vi har sett några fall där Bash skriver om ett kommando på olika sätt innan det slutligen exekveras. Till exempel skrivs *.tex om till en alfabetiskt sorterad lista av de filer i den nuvarande katalogen vars namn slutar på ''.tex''. I detta avsnitt ska vi diskutera åtskilliga andra typer av omskrivningar som Bash kan göra med en kommandorad.
Tecknet ~ skrivs om till namnet på den
egna hemkatalogen i konstruktioner som
~/dikter. Omskrivningen sker bara om
tildetecknet kommer i början av ett argument.$ echo Min hemkatalog heter ~
Min hemkatalog heter /home/göran
$ cd ~/dikter
$ pwd
/home/göran/dikter
$På motsvarande sätt skrivs
~eva om till namnet på eva:s hemkatalog
ifall det finns en användare med namnet eva.$ echo ~eva/post
/home/eva/post
$ echo hej~
hej~
$ echo ~=
~=
$I de båda sista exemplen skedde ingen omskrivning.
Om kommandoraden innehåller ett uttryck av formen
$(kommando),
så skriver Bash om detta till utdatan från
kommandot kommando.$ echo Dagens datum är $(date)
Dagens datum är tis feb 17 18:30:20 CET 1998
$Figur 6.2 visar vad som hände
när kommandot ovan exekverades:
argumentet $(date) skrevs om till
tis feb 17 18:30:20 CET 1998 innan echo anropades.
Så här kan man få date att ange
dagens datum på formen ååmmdd:$ date +%y%m%d
980217
$I nästa exempel gör vi en
kopia av filen bellman.
Namnet på kopian märks med dagens datum:$ cp bellman kopia.$(date +%y%m%d).bellman
$ ls
bellman kopia.980217.bellman lenngren
$I gamla Bourne-skalet skrev man `kommando`
i stället för $(kommando). Av kompatibilitetsskäl
fungerar detta också i Bash.
Om ett argument i kommandoraden inleds med tecknet #,
så stryks detta tecken och allt som kommer efter det på samma rad
innan kommandot utförs. Man använder detta för att kunna skriva
kommentarer till kommandon.$ date # Detta är en kommentar!
sön okt 12 23:05:29 CEST 1997
$ echo hej #på dej
hej
$ echo hej#på dej
hej#på dej
$
Ett argument av formen
prefix{ord1,ord2,...}suffix skriver Bash om till
orden prefixord1suffix prefixord2suffix osv.
Alla ord som räknas upp inom klamrarna bildar alltså nya ord genom att
prefix och suffix läggs till i början respektive på slutet.$ echo Sål{d,l,t}
Såld Såll Sålt
$ echo H{e,a}l{,a,t}!
Hel! Hela! Helt! Hal! Hala! Halt!
$ echo kap{1,2,5{A,B},23}
kap1 kap2 kap5A kap5B kap23
$
Som vi redan sett kan Bash hålla reda på alias för kommandon.
Om man till exempel har gett kommandot
alias ls='ls -NF -color' och sedan vid prompten
skriver ett kommando som inleds med ls,
så byter Bash ut ''ls'' mot
''ls -NF -color'' innan kommandot exekveras.
(Alias är ett primitivt men trots det ganska användbart
hjälpmedel.
Betydligt kraftfullare är möjligheten att
skriva funktioner i Bash.Följande exempel visar hur man kan få rm att
automatiskt ta med flaggan -i:$ alias rm='rm -i'
$ rm bellman
rm: ta bort "bellman"? n
$ ls
bellman kopia.980217.bellman lenngren
$
Det är inte svårt att skicka text som indata till ett program.
Man kan helt enkelt låta echo skriva ut texten
till programmet via en rörledning. Men det finns ett annat
sätt, som ibland är bekvämare, nämligen att
omdirigera indatan med tecknen <<.
I följande exempel
skickar vi texten Eva Thulin som indata till programmet
hej från sida
:$ hej <<EOF
> Eva Thulin
> EOF
Hej, Eva Thulin!
$Efter tecknen << skriver man ett godtyckligt ord.
Ofta väljer man EOF, som står för ''End Of File''.
Därefter skriver man den text som ska utgöra kommandots indata.
Man avslutar med att på en ny rad skriva samma ord som man
skrev efter tecknen <<.
På detta sätt kan indatan till ett kommando skrivas
i anslutning till själva kommandot.
#!/bin/bash
TAL=10
cat <<- EOF
Hej, $1!
Idag är det den $(date).
Visste du att $TAL/2=$((TAL/2))?
Hejdå!
EOF
Programmet hejsan ovan skriver ut fyra rader text
med hjälp av cat.
För att göra programmet lättläst har vi satt ett
tabulatorsteg före varje rad av texten.
Minustecknet efter tecknen << är en signal till skalet
att dessa tabulatorsteg ska tas bort innan texten skickas genom
cat.$ hejsan
Hej, Göran!
Idag är det den sön feb 22 19:01:17 CET 1998.
Visste du att 10/2=5?
Hejdå!
$Körningen ovan visar att några av de vanliga
omskrivningarna kan användas i den text som
omdirigeras med <<. Om man beskyddar
någon del av ordet efter <<, så undviker
skalet dessa omskrivningar.
#!/bin/bash
cat <<- 'EOF'
Hej, $1!
Idag är det den $(date).
EOF
Programmet ovan ger följande utskrift:$ hejsan
Hej, $1!
Idag är det den $(date).
$
Man kan koppla samman ett antal kommandon genom
att låta dem omges av parenteser. Därigenom
får kommandona en gemensam in- och utdata.
Betrakta tex följande två kommandon:$ echo -n 'Dagens datum är ' ; date
Dagens datum är sön feb 22 19:18:57 CET 1998
$Om vi vill skicka utskriften från dessa kommandon genom
wc, så kan vi inte göra så här:$ echo -n 'Dagens datum är ' ; date | wc
Dagens datum är 1 6 29
$Vad som hände var att bara det sista kommandots utdata skickades till
wc. Bash prioriterar nämligen operatorn |
högre än ;. Med hjälp av parenteser går det bättre:$ (echo -n 'Dagens datum är ' ; date) | wc
1 9 45
$Kommandon som kopplats samman med hjälp av parenteser
exekveras i ett subskal. Detta innebär att eventuella
förändringar av variabelvärden eller nuvarande katalog mellan
parenteserna inte är bevarade efter att
kommandona kört färdigt.
Om man vill att kommandona ska köras i det nuvarande
skalet i stället för i ett subskal, så ska man använda
klamrar i stället för parenteser; det sista kommandot
måste då avslutas med ett semikolon.$ pwd
/home/göran/dikter
$ ( cd /etc ; ls -l passwd )
-rw-r--r-- 1 root root 1291 nov 25 14:37 passwd
$ pwd
/home/göran/dikter
$ { cd /tmp ; ls ; }
emacs.gz
$ pwd
/tmp
$ Ändringen av den nuvarande katalogen skedde
i ett subskal i det första exemplet,
och då bevarades inte ändringen.
Den andra gången bevarades dock ändringen.
Ett annat skäl att koppla samman kommandon så här är
att de då kan köras efter varandra i bakgrunden.
Nedan startar vi två jobb i bakgrunden;
det första väntar i 30 sekunder och skriver därefter ut
vilka filer som finns i den nuvarande katalogen, medan det
andra dekomprimerar filen emacs.gz.$ (sleep 30 ; ls ) &
[1] 7842
$ gunzip emacs.gz &
[2] 7844
$ jobs
[1]- Running ( sleep 30; ls -NF --color ) &
[2]+ Running gunzip emacs.gz &
$ echo Nu emacs*
är det klart
Nu är det klart
[1]- Done ( sleep 30; ls -NF --color )
[2]+ Done gunzip emacs.gz
$Vid kommandot jobs ovan ser man att de båda jobben är
i full gång. Men medan jag skrev in nästa kommando, kom utskriften
av ls från första jobbet emellan. Obekymrad om detta fullbordade
jag mitt kommando,
echo Nu är det klart. Innan nästa prompt skrevs ut gav Bash
besked om att de båda jobben var klara.
(Faktum är att jobb nummer två måste ha blivit klart före
jobb nummer 1 eftersom ls inte skrev ut emacs.gz.)
Övning. Ändra prompternas utseende till något som passar dig.
Övning. Skapa ett alias med namnet ll för ls -l. Prova det!
Övning. Beräkna 1048575/341 i Bash.
Antag att några av användarna på datorn samarbetar om att skriva en bok. Då ska just dessa användare, men inga andra, ha rätt att ändra i de filer som innehåller materialet till boken. Ibland är det alltså önskvärt att mer än en användare, men ändå inte alla, ska tilldelas vissa befogenheter över en fil eller katalog. Detta är möjligt tack vare något som kallas för grupper. En grupp består av ett antal användare på systemet. Det kan till exempel finnas en grupp med namnet dikt, vars medlemmar arbetar med att sammanställa en diktsamling.
Om kommandot groups anropas utan argument, så skrivs det
ut vilka grupper man själv är medlem i.$ groups
göran floppy dikt
$Jag är tydligen medlem i grupperna
göran, floppy och dikt.
Om groups anropas med ett eller flera användarnamn som argument,
så får man veta vilka grupper var och en av
dessa användare är medlem i.$ groups eva göran
eva : eva staff dikt
göran : göran floppy dikt
$Användaren eva är alltså medlem i grupperna
eva, staff och dikt.
Varje användare tillhör minst en grupp. Men även om man kan vara medlem i flera grupper, så ''befinner man sig'' vid varje tillfälle bara i en grupp. Den grupp användaren direkt efter inloggningen befinner sig i kallas för hennes login-grupp. På Debian GNU/Linux-system finns det för varje användare en grupp vars namn är detsamma som hennes användarnamn och i vilken hon själv är den enda medlemmen. Vanligtvis är det denna grupp som är hennes login-grupp. (Skälet till att alla användare har en ''egen grupp'' är att det därmed blir möjligt för dem att slentrianmässigt ge gruppen samma rättigheter till sina filer och kataloger som de själva har.)
Kommandot id ger information om grupper och identiteter:$ id
uid=1000(göran) gid=1000(göran) grupper=1000(göran),25(floppy),101(dikt)
$Det kan vara värt att veta, att UNIX internt identifierar
en användare inte med hjälp av hennes användarnamn, utan med hjälp
av ett nummer som kallas för hennes användaridentitet (uid).
Likaså representeras grupper internt med ett nummer
som kallas för gruppidentiteten (gid).
Min användaridentitet är 1000 och jag befinner mig
just nu i gruppen med gruppidentitet 1000.
Med hjälp av kommandot newgrp kan man
byta nuvarande grupptillhörighet.$ newgrp dikt
$ id
uid=1000(göran) gid=101(dikt) grupper=1000(göran),25(floppy),101(dikt)
$För att återgå till den förra grupptillhörigheten
ska man ge kommandot exit.$ exit
$ id
uid=1000(göran) gid=1000(göran) grupper=1000(göran),25(floppy),101(dikt)
$
Flaggan -d anger att kommandot ls
ska ge information om kataloger
snarare än om filerna de innehåller.$ ls -ld dikter
drwxrwxr-x 3 göran göran 1024 feb 20 13:19 dikter/
$Jag ändrar nu grupptillhörigheten för katalogen
dikter från göran till dikt.
Kommandot för detta är chgrp.$ chgrp dikt dikter
$ ls -ld dikter
drwxrwxr-x 3 göran dikt 1024 feb 20 13:19 dikter/
$Hädanefter kan eva, som också är medlem i gruppen dikt,
skapa och radera filer i katalogen dikter.
Kommandot för att byta ägare för en fil är chown, men det är bara root som byta ägare för filer - annars skulle man ju kunna ''stjäla'' filer från andra! Likaså måste man tillhöra en viss grupp för att kunna associera filer eller kataloger med gruppen.
Om man vill att kataloger och filer ska få grupptillhörigheten
dikt direkt när de skapas, så ska man se till att
man befinner sig i denna grupp.$ newgrp dikt
$ mkdir kopior
$ ls -ld kopior
drwxrwxr-x 2 göran dikt 1024 mar 8 13:49 kopior/
$ exit
exit
$
För att byta användaridentitet till användarnamn
ska man ge kommandot
su användarnamn. Om argumentet användarnamn
är root, så kan det utelämnas.$ su
Lösenord:
root@fafner# id
uid=0(root) gid=0(root) grupper=0(root)
root@fafner# exit
exit
$De personer som är systemadministratörer på datorn
brukar arbeta som ''vanliga användare'' en stor
del av tiden. När de behöver utökade rättigheter
går de över till användaridentiteten root genom att ge
kommandot su.
Antag att vi flyttar filen
dikter.tgz till katalogen kopior:$ ls
bellman dikter/ dikter.tgz kopior/ lenngren
$ mv dikter.tgz kopior/nr1
$Detta kan vålla problem eftersom vissa
kanske förväntar sig att finna
dikter.tgz där den fanns tidigare.
För att undvika sådana problem kan man göra
en symbolisk länk från den ursprungliga till den nya
positionen för filen. En symbolisk länk är väsentligen ett
meddelande om ny adress - ''jag finns inte här längre,
jag finns där''.
Symboliska länkar används flitigt på UNIX-system,
bland annat för att man ska
kunna vara säker på att alla program
ska hitta de filer de behöver.
Kommandot för att skapa en symbolisk länk
är ln -s.$ ln -s kopior/nr1 dikter.tgz
$Ovan skapade jag en symbolisk
länk till filen kopior/nr1.
Länkfilen, som heter dikter.tgz, listas av
ls ungefär som en vanlig fil:$ ls
bellman dikter/ dikter.tgz@ kopior/ lenngren
$Att dikter.tgz är en symbolisk länk markeras
ovan med tecknet @ efter dess namn.
Då vi begär utförlig information
om dikter.tgz, ser vi att den är en hänvisning till
kopior/nr1: $ ls -l dikter.tgz
lrwxrwxrwx 1 göran göran 10 mar 8 22:21 dikter.tgz -> kopior/nr1
$Det första
tecknet i filskyddskoden är l för symboliska länkar.
Vad händer ifall någon försöker använda filen dikter.tgz?
Låt oss prova!$ tar -ztvf dikter.tgz
drwxrwxr-x göran/göran 0 1998-02-27 19:43 dikter/
-rw------- göran/göran 372 1998-02-01 17:12 dikter/bellman
-rw-rw-r-- göran/göran 649 1998-02-01 17:12 dikter/lenngren
$De flesta kommandon skickas automatiskt
vidare till den riktiga filen när de använder en symbolisk länk.
Detta var vad som skedde vid kommandot ovan; tar
kördes i själva verket på filen kopior/nr1.
Ett undantag från denna
regel är rm: om vi ger kommandot rm dikter.tgz, så
raderas länkfilen i stället för test/ny.fil.$ rm dikter.tgz
$ ls
bellman dikter/ kopior/ lenngren
$ ls kopior
nr1
$Det kan också förekomma symboliska länkar till kataloger.$ ln -s kopior gammalt
$ ls
bellman dikter/ gammalt@ kopior/ lenngren
$Nu är gammalt en symbolisk länk till katalogen kopior.
Vi kan göra samma saker med gammalt som vi kan göra
med kopior:$ ls gammalt
nr1
$ cd gammalt
$ pwd
/home/göran/gammalt
$ ls -l
total 1
-rw-rw-r-- 1 göran göran 829 mar 1 22:58 nr1
$
Om man raderar en fil eller katalog
som det finns symboliska länkar till, så
kommer dessa symboliska länkar att peka ut i tomma intet.$ cd
$ rm -r kopior
$ ls gammalt
gammalt@
$ cd gammalt
bash: cd: gammalt: Filen eller katalogen finns inte
$ rm gammalt
$ ls
bellman dikter/ lenngren
$
Informationen om en fil (bland annat filens längd, datum för senaste
ändring, filen rättigheter samt var på lagringsmediet filen
placerats) lagras i något som kallas för en inod.
Filens namn lagras inte i inoden. Istället
har varje inod ett nummer, dess inodsnummer.
Kopplingen
mellan ett filnamn och mosvarande inod görs genom att
systemet i den katalog där filen finns lagrar enbart
filens namn och motsvarande inodsnummer - själva inoden
kan vara lagrad på någon annan plats.
Vilket inodsnummer som hör till ett givet filnamn skrivs ut
om man anger flaggan -i till ls.$ ls -i
157097 bellman 157098 dikter/ 157138 lenngren
$Utskriften betyder att filen bellman har
inodsnummer 157097 osv.
På sätt och vis kan man hävda att inoden är filen,
medan filens namn är ett slags länk,
en hård länk, till inoden.
Ingenting hindrar att man har mer än en hård länk
till en och samma fil/inod.
Därigenom kan en fil ha flera olika namn.
Kommandot för att skapa en ny hård länk
till en fil är ln (utan flaggan -s).$ ln bellman sång
$ ls -i
157097 bellman 157098 dikter/ 157138 lenngren 157097 sång
$Nu är sång en hård länk till filen bellman,
något som syns genom att de båda filerna har samma inodsnummer
i utskriften ovan.
Detta innebär att sång och bellman
är två olika (men helt likvärdiga) namn för en och samma fil/inod.
När ls anropas med flaggan -l, skrivs antalet
hårda länkar till varje fil ut efter dess skyddskod.$ ls -l
total 4
-rw------- 2 göran göran 372 feb 1 16:48 bellman
drwxrwxr-x 2 göran göran 1024 feb 27 19:43 dikter/
-rw-rw-r-- 1 göran göran 649 feb 1 15:53 lenngren
-rw------- 2 göran göran 372 feb 1 16:48 sång
$Siffran 2 som anges för sång och bellman i listningen
ovan, betyder att det finns två hårda länkar till dessa filer.
Låt oss skapa ytterligare en hård länk till dem:$ ln sång fredman
ls -li
total 5
157097 -rw------- 3 göran göran 372 feb 1 16:48 bellman
157098 drwxrwxr-x 2 göran göran 1024 feb 27 19:43 dikter/
157097 -rw------- 3 göran göran 372 feb 1 16:48 fredman
157138 -rw-rw-r-- 1 göran göran 649 feb 1 15:53 lenngren
157097 -rw------- 3 göran göran 372 feb 1 16:48 sång
$De tre filnamnen fredman, sång och bellman
är hårda länkar till inoden med nummer 157097.
Om man raderar
en hård länk, så påverkas inte de andra länkarna till samma inod
(inoden tas bort först när samtliga länkar till den raderats).$ rm sång
$ ls
bellman dikter/ fredman lenngren
$ rm fredman
$ ls -l
total 3
-rw------- 1 göran göran 372 feb 1 16:48 bellman
drwxrwxr-x 2 göran göran 1024 feb 27 19:43 dikter/
-rw-rw-r-- 1 göran göran 649 feb 1 15:53 lenngren
$
Hårda länkar är inte lika vanligt förekommande som symboliska. De används främst när ett program ska fungera på olika sätt beroende på vilket namn det anropas under. Symboliska och hårda länkar är lika såtillvida att de båda kan ge en och samma fil olika namn. Det finns dock några skillnader. För det första kan det inte förekomma hårda länkar mellan filer som ligger på olika fysiska lagringsmedium som tex olika hårddiskpartitioner. Det kan inte heller förekomma hårda länkar mellan kataloger. En fördel med hårda länkar är att olika hårda länkar till en och samma inod är fullständigt likvärdiga - för symboliska länkar fungerar länkfilen i vissa avseenden annorlunda än den verkliga filen.
Ett alternativt sätt att ange filskyddskoder är att
använda siffror.
Det fungerar på så sätt att läsrättigheten är värd fyra poäng,
skrivrättigheten två poäng och rätten att exekvera
en poäng. Genom att lägga samman poängtalen får man en
siffra som kan representera skyddskoden.
Till exempel motsvarar r-x siffran 4+1=5,
r-- motsvarar 4 och --- motsvarar 0.$ chmod 764 bellman
$ ls -l bellman
-rwxrw-r-- 1 göran göran 372 feb 1 16:48 bellman*
$Den första siffran i talet 764
gäller ägarens rättigheter, den andra gruppens
och den tredje de övrigas.
Det återstår att berätta om en viktig sak i samband med
rättigheter. För att ta ett exempel, filen /etc/shadow
innehåller alla användares lösenord (om än i krypterad form).
Bara systemadministratören har rätt att läsa och ändra den filen.
Men när jag byter lösenord måste ju den filen med nödvändighet
ändras. Hur går det till? Svaret får vi genom
att studera filskyddskoden för passwd.
Vi lokaliserar var den fil som innehåller programmet
passwd finns med hjälp av kommandot which,
och läser sedan av dess skyddskod:$ which passwd
/usr/bin/passwd
$ ls -l /usr/bin/passwd
-rwsr-xr-x 1 root root 33288 apr 19 10:20 /usr/bin/passwd*
$Det intressanta här är tecknet s i skyddskoden för passwd.
När ett program exekveras, ges det vanligtvis
samma befogenheter som den som startade programmet har.
Om tex användaren eva kör Emacs, så får
denna Emacs-process bara ändra de filer som eva får ändra.
Men om det står s i stället för x i skyddskoden för
ägaren till en viss fil, så betyder det att
när filen körs som ett program, så ges programmet
samma rättigheter som filens ägare har.
Bokstaven ''s'' står här för ''sätt användaridentitet - setuid''.
När programmet passwd körs, så har det alltså
samma rättigheter som root, vilket betyder att det
får göra nästan vad som helst. (Minsta lilla fel i programmet
passwd skulle därför vara ödesdigert. En av de främsta
orsakerna till säkerhetsproblem i UNIX-system är när det finns
brister i program som har s-biten satt.)
På motsvarande sätt kan ett program ha en s-bit i skyddskoden
för grupp. Då står ''s'' för ''sätt gruppidentitet - setgid'', och
processen tilldelas de befogenheter som den grupp
programfilen är associerad med har.
Förutom setuid och setgid finns en tredje specialrättighet
som kan tilldelas filer och kataloger, nämligen fastbiten
(''sticky bit'').
Egentligen är den en kvarleva från UNIX barndom.
Om en katalog har sin fastbit satt, så får ingen användare
(med undantag för katalogens ägare)
radera någon annan användares filer i den katalogen, vilket
de vanligtvis får ifall de har skrivrättighet till katalogen.
Betrakta till exempel katalogen /tmp:$ ls -ld /tmp
drwxrwxrwt 3 root root 1024 mar 9 11:25 /tmp/
$Vi ser att fastbiten är satt eftersom ls skriver
bokstaven t sist i skyddskoden.
I och med att ''övriga'' har skrivrättighet till
/tmp kan jag skapa och radera filer där,
men jag kan inte ändra i någon annans filer
eftersom fastbiten är satt.
För att sätta fastbiten använder man chmod
med argumentet o+t. Setuid sätts med
argumentet u+s, setgid med g+s.
Specialrättigheter kan också sättas med en siffra.
Då är setuid värt 4 poäng, setgid 2 poäng
och fastbiten 1 poäng. Poängsumman sätts framför
de tre siffror som gäller de vanliga rättigheterna:$ chmod 5764 bellman
$ ls -l bellman
-rwsrw-r-T 1 göran göran 372 feb 1 16:48 bellman*
$Siffran 5 är 4+1, vilket betyder att setuid och fastbiten
sätts på. Därför står det nu ''s'' och ''T'' i filskyddskoden.
Att ls skriver ett stort T beror på att x-biten
för ''övriga'' inte är satt. Likaså skrivs stora S när
setuid (eller setgid) är satt medan x-biten för ägaren
(gruppen) inte är satt. Låt oss återställa skyddskoden
för bellman till ett förnuftigt värde:$ chmod 664 bellman
$ ls -l bellman
-rw-rw-r-- 1 göran göran 372 feb 1 16:48 bellman
$
Hur avgörs det vilken skyddskod nya filer får?
Svaret på denna fråga får vi av kommandot umask.$ umask
002
$Värdet som skrivs ut av umask talar
om vilka rättigheter som ska tas bort.
Den nuvarande inställningen innebär att skrivrättigheten
tas bort för ''övriga''. $ mkdir ny.katalog
$ ls -ld ny.katalog
drwxrwxr-x 2 göran göran 1024 mar 9 13:03 ny.katalog/
$Som synes är alla rättigheter satta utom skrivrättigheten för ''övriga''.
Låt oss ändra värdet
så att skrivrättigheten tas bort för gruppen medan
alla rättigheter tas bort för ''övriga'':$ umask 027
$ cp bellman ny.fil
$ ls -l ny.fil
-rw-r----- 1 göran göran 372 mar 9 13:06 ny.fil
$ rm -r ny.*
$I rättigheterna för ny.fil saknas, förutom de rättigheter som vi ville
ta bort, även alla rättigheter att exekvera.
Skälet till detta är att nya filer inte automatiskt
får exekveringsrättigheter eftersom det inte är säkert
att de faktiskt är program som kan exekveras.
|
Under UNIX kommunicerar man med hårdvaruenheter via
en specialfil i katalogen /dev.
Ett exempel på detta är filen /dev/fd0.$ ls -l /dev/fd0
brw-rw---- 1 root floppy 2, 0 maj 28 02:49 fd0
$Tecknet b i som skrivs ut före filskyddskoden anger
att det rör sig om en så kallad blockspecialfil.
Den första serieporten motsvaras av filen /dev/ttyS0.$ ls -l /dev/ttyS0
crw-rw---- 1 uucp dialout 4, 64 okt 12 20:38 /dev/ttyS0
$Tecknet c innebär att /dev/ttyS0 är en
så kallad teckenspecialfil.
Specialfiler av typen FIFO (''först in, först ut'')
används för rörledningar. Ett exempel ges av filen
/dev/xconsole:$ ls -l /dev/xconsole
prw-r--r-- 1 root root 735 mar 9 12:28 /dev/xconsole
$Den återstående filtypen är ''socket'', som används i
nätverkskommunikation. Som exempel tar vi filen /dev/log:$ ls -l /dev/log
srw-rw-rw- 1 root root 0 mar 6 13:22 /dev/log=
$
Antag att jag har en diskett med det innehåll som visas i figur
.
På disketten finns filerna svamp.html och
RMAIL. Dessutom finns där två kataloger,
dokument och program,
som innehåller ytterligare några filer.
Jag vill nu läsa av filerna som finns på disketten.
Problemet är att
man i UNIX bara kan komma åt filer
som finns någonstans
i hierarkin av kataloger under rotkatalogen.
Men vill man använda en diskett, en extra hårddisk,
en CD-skiva eller dylikt,
så kan man montera den på en katalog i det
ordinarie filsystemet.
Om jag tex monterar min diskett på katalogen
/floppy, så ser det ut som om
de filer och kataloger som finns på disketten
ligger i den katalogen i det ordinarie filsystemet.
Då kan jag tex ge kommandot more /floppy/svamp.html
för att läsa filen svamp.html på disketten,
eller kommandot cp /floppy/svamp.html /home/göran
för att kopiera den till min hemkatalog.
|
mount -t typ enhet katalog
där typ står för den typ av filsystem som ska monteras,
enhet för den enhet filsystemet finns på och
katalog för den katalog filsystemet ska monteras på.
Katalogen katalog måste existera. Den behöver inte vara tom,
men det som eventuellt finns i den kan inte kommas åt
så länge något är monterat på den.
När filsystemet inte längre behöver vara monterat ska det monteras ned igen
med kommandot umount katalog, där katalog
står för den katalog filsystemet är monterat på.
Om min diskett använder typen minix, så blir kommandot
för att montera den mount -t minix /dev/fd0 /floppy,
och kommandot för att montera ned den är
umount /floppy.
Men nu kommer vi till det riktigt stora problemet:
av säkerhetsskäl är det vanligtvis bara
systemadministaratören som får montera kataloger!
Systemadministaratören skulle kunna göra så här:root@fafner# mount -t minix /dev/fd0 /floppy
Hur ska jag som vanlig användare komma åt innehållet
på min diskett? Jo, kanske har systemadministaratören
gjort en inställning som tillåter användarna att
montera disketter och CD-skivor, om än
under restriktiva former.
För att kontrollera om det är så ska vi
studera filen /etc/fstab.$ cat /etc/fstab
#<enhet> <katalog> <typ> <flaggor> <> <pass>
/dev/sda1 / ext2 defaults 0 1
/dev/sda7 none swap sw 0 0
proc /proc proc defaults 0 0
/dev/sda3 /usr ext2 defaults 0 2
/dev/sda2 /dosc vfat defaults 0 0
/dev/fd0 /floppy vfat user,noauto 0 0
/dev/fd0 /floppy/minix minix user,noauto 0 0
/dev/fd0 /floppy/ext2 ext2 user,noauto 0 0
/dev/cdrom /cdrom iso9660 user,ro 0 0
/dev/sda5 /home ext2 defaults 0 2
fasolt:/home/eva /home/eva nfs defaults 0 0
$Det är systemadministaratören som skapar filen
/etc/fstab. Filen är främst till för att
ange vilka filsystem som ska monteras varje gång datorn
startas om. Men om ett filsystem ofta monteras på ett
visst ställe, så kan det också beskrivas i
/etc/fstab, och då kan kommandot för att montera
det förenklas - man behöver bara ge kommandot
mount katalog ifall det anges
i /etc/fstab vad som brukar monteras på katalog.
Varje rad (utom de som inleds med tecknet #)
motsvarar ett filsystem. Alla utom de som har
ordet noauto under rukriken ''flaggor''
monteras automatiskt vid uppstarten.
Under rubriken ''enhet'' anges på vilken fysisk enhet
filsystemet finns, under ''katalog'' var det ska monteras,
under ''typ'' vilken typ av filsystem det gäller.
I den näst sista kolumnen ska det stå
en nolla (så vitt jag vet används detta inte längre till något).
Den sista kolumnen anger ifall man vill att filsystemet
ska genomsökas efter eventuella fel innan det monteras.
En nolla betyder att det inte ska felsökas,
annars ska det stå en etta för filsystemet som
ska innehålla rotkatalogen och en tvåa
för alla andra.
Apropå enhet: hårddiskar brukar heta
/dev/hda, /dev/hdb, /dev/sda
eller dylikt. Om hårddisken är uppdelad på flera
delar (så kallade partitioner), så
har delarna nummer 1,2,3 osv.
Men vad som intresserar oss nu är ifall det
under rubriken ''flaggor'' står user,
för i så fall får vanliga användare montera
det filsystem som beskrivs på den raden.
Av utskriften ovan att döma får jag montera
disketter i första diskettenheten.
Om filsystemet på disketten är av typen
vfat så får det monteras på katalogen
/floppy, om det är av typen ext2
så får det monteras på /floppy/ext2
och om typen är minix så
får det monteras på /floppy/minix.
Så här kan jag alltså göra:$ mount /floppy/minix
$ cd /floppy/minix
$ ls
RMAIL dokument/ program/ svamp.html
$ cp svamp.html /home/göran
$ cd program
$ ls
Makefile hejvärlden.c nim.c
$ pwd
/floppy/minix/program
$ cp /home/göran/bellman .
$ ls
Makefile bellman hejvärlden.c nim.c
$ umount /floppy/minix
umount: /floppy/minix: device is busy
$ cd /floppy
$ umount /floppy/minix
$ ls minix
$Först monterade jag min diskett som /floppy/minix.
Jag kopierade filen svamp.html från disketten till
min hemkatalog, och filen bellman från min hemkatalog
till katalogen program på disketten.
Därefter försökte jag montera ned disketten,
men det gick inte eftersom jag befann mig i den katalog
disketten var monterad på (eller snarare i en
underkatalog till den). När jag gick bort från katalogen
/floppy/minix och försökte igen, så gick det bättre.
Efter att disketten monterats ned är katalogen /floppy/minix
tom.
Observera att disketten absolut inte får tas ur diskettenheten
så länge den är monterad!
Om man brutalt tar ur
disketten utan att först montera ned den, så kan det inträffa att
vissa filer bara finns med till hälften eftersom
Linux ofta sparar saker i minnet
en stund innan de skrivs över till disketten.
Med hjälp av kommandot df kan man få reda på hur mycket
utrymme som finns fillgängligt på de filsystem som är
monterade.$ df -h
Filesystem Size Used Avail Capacity Mounted on
/dev/sda1 304M 34M 254M 12% /
/dev/sda3 1.1G 433M 647M 40% /usr
/dev/sda2 314M 6.6M 307M 2% /dosc
/dev/sda5 987M 662M 274M 71% /home
fasolt:/home/eva 191M 161M 19M 89% /home/eva
/dev/hdc 592M 592M 0 100% /cdrom
$Till exempel är femte partitionen
på hårddisken /dev/sda
monterad på katalogen /home.
Utrymmet på partitionen är 987 megabyte,
varav 662 megabyte är använt just nu.
LATEX är ett professionellt typsättningsprogram. Det är ett av de främsta programmen på UNIX-system, i klass med GCC, Emacs och GIMP. Det är oerhört anvancerat och komplicerat, men i gengäld är LATEX fullständigt överlägset alla ordbehandlingsprogram vad gäller flexibilitet och kvalitet på de dokument som framställs.
LATEX är i första hand till för att typsätta artiklar, uppsatser, brev och böcker. Det går visserligen att tillverka tex reklambroschyrer och visitkort också, men man får inte så mycket hjälp med detta av LATEX.
I motsats till de flesta ordbehandlare är
LATEX inte ett WYSIWYG-program. I stället använder man
ett språk av samma typ som HTML, det som används i webbsidor.
Man kan använda vilken textredigerare som helst för att
skapa en LATEX-fil, som kan heta tex hej.tex.
Sedan låter man LATEX behandla filen och skapa en ny fil
med namnet hej.dvi. Ändelsen .dvi står
för ''device independent''. Dvi-filen är i ett grafikformat
som kan visas på datorskärmen med programmet xdvi,
eller vidarebehandlas för en skrivare. Vanligtvis använder man
programmet dvips för att översätta dvi-filen till
postscript för att sedan skicka postscriptfilen till en
skrivare.
Låt oss säga att hej.tex ser ut så här:
\documentclass[12pt]{article}
\usepackage[swedish]{babel}
\usepackage{t1enc}
\begin{document}
Hej, allihopa! Detta är mitt första \LaTeX-dokument.
\end{document}
Själva texten är det som kommer mellan \begin{document}
och \end{document},
allt annat är kommandon till LATEX.
Så här typsätter vi dokumentet:$ latex hej.tex
This is TeX, Version 3.14159 (C version 6.1)
(hej.tex
LaTeX2e <1996/12/01>
Babel <v3.6h> and hyphenation patterns for american, swedish, loaded.
(/usr/lib/texmf/tex/latex/base/article.cls
Document Class: article 1996/10/31 v1.3u Standard LaTeX document class
(/usr/lib/texmf/tex/latex/base/size12.clo))
(/usr/lib/texmf/tex/generic/babel/babel.sty
(/usr/lib/texmf/tex/generic/babel/swedish.ldf
(/usr/lib/texmf/tex/generic/babel/babel.def)))
(/usr/lib/texmf/tex/latex/base/t1enc.sty)
No file hej.aux.
[1] (hej.aux) )
Output written on hej.dvi (1 page, 356 bytes).
Transcript written on hej.log.
$ dvips -o hej.ps hej.dvi
This is dvipsk 5.58f Copyright 1986, 1994 Radical Eye Software
' TeX output 1997.10.22:1525' -> hej.ps
<tex.pro>. [1]
$Nu har vi skapat en postscriptfil hej.ps,
som kan skrivas ut på varje postscriptskrivare.
Med hjälp av programet ghostscript kan postscriptfiler
skrivas ut på nästan vilka skrivare som helst,
och de kan dessutom visas på datorskärmen med extra hjälp från
programmet gv. Under X kan man titta på dvi-filen
med kommandot xdvi hej.dvi & eller på
postscript-filen med kommandot gv hej.ps &.
Resultatet ser ut ungefär så här:
Hej, allihopa! Detta är mitt första LATEX-dokument.Det finns oerhört mycket mer att säga om LATEX, men vi får spara det till ett annat tillfälle!
SGML är en ISO standard (ISO 8879:1986) för att beskriva dokument på ett sätt som datorer och människor kan förstå. Detta betyder att SGML inte är ett filformat som t.ex. TEX, .doc eller LATEXutan ett sätt att beskriva dokumentsstruktur. SGMLtools är en samling program som gör att dokument som har en sådan beskrivning kan tryckas, användas och publiceras.
Den mest använda SGML beskrivningen är HTML, som är konstruerad för att publicera material på internet. Eftersom de flesta dokument som vanliga människor skriver inte skall publiceras på internet så är det ganska naturligt att SGMLtools har valt DocBook som sin dokumenttyps beskrivning. Dokumenttypen DocBook är konstruerad utifrån krav från elektronik- och högteknologiföretag av Davenport gruppen (ArborText, Fujitsu, O'Reilly and Associates, mfl.).
Ett dokument skrivet enligt DocBook standarden kan bearbetas i många program innom SGMLtools används JADE för bearbetningen. JADE är vad man kallar en validerande SGML översättare, detta betyder att den först kollar att det du skrivit följer den SGML dokumenttypsbeskrivning du angivit (i SGMLtool är detta DocBook). Där efter så gör JADE om ditt dokument till objekt vilka skickas igenom ett filter (ett stilark) som gör vissa saker med dokumentet och sedan skickas slutresultatet till en fil.
För att skriva ett dokument så behöver man inte veta så här mycket teori, men det hjälper för att förstå DocBook.
Låt oss säga att hej.sgml ser ut så här:
<!DOCTYPE book PUBLIC "-//Davenport//DTD DocBook V3.0//EN" [
]>
<book id="hej" lang="svse">
<title>En intorduktion till DocBook</title>
<bookinfo>
<title>En introduktion till DocBook</title>
</bookinfo>
<toc></toc>
<chapter id="kapitel1">
<title>Hej</title>
<para>
Mitt första dokument som är skrivet i DocBook!
</para>
<sect1 id="Text">
<title>DocBook är mycket struktur, lite layout</title>
<para>
För att skriva i DocBook måste man i första han tänka på
struktur och inte på hur saker och ting ser ut. Det är
inte upp till dig som författare att bestämma hur texten
ser ut, utan det avgörs av den som skriver stilbladet.
</para>
</sect1>
</chapter>
</book>
$ sgmltools -b ps hej.sgml
Nu har vi sett ett SGML dokument som är skrivet enligt DocBooks regler, men vad gör de olika raderna egentligen?
<!DOCTYPE book PUBLIC "-//Davenport//DTD DocBook V3.0//EN" [ ]>
Är den första raden i alla dokument som bearbetas av SGMLtools. <!DOCTYPE är ett nyckelord som SGMLtools använder för att hitta vad det första elementet i filen är. Texten PUBLIC berättar för SGMLtools att det är en publik dokumenttyp som finns med i SGMLtools katalog över dokumenttyper. Texten "-//Davenport//DTD DocBook V3.0//EN" talar om för SGMLtools vilken typ av dokument det är.
Denna texten är uppbyggd i ett par sektioner som är åtskilda av // det första är - tecknet. Det är satt där för att visa att DocBook inte är registrerad i ISO katalogen över dokumenttyper, annars skulle det ha varit ett +. Andra delen är ägaren eller tillverkaren av dokumenttypen, detta är altså Davenport gruppen. Nästa del är texten DTD vilket står för document type definition åtföljt av namnet på den dokumenttyp som vi har skrivit dokumentet i. EN betyder engelska, och kommer från att dokumenttypen är skriven på engelska (detta har inget med språket på dokumentet att göra)!
Mellan [ och ]> så kan man skriva utökningar av dokumenttypen som bara gäller i detta dokumentet.
Tidigare så nämde vi element ett element i texten är en logisk sektion som är markerad med s.k. taggar. En tag är T.ex. <book> efter varje tag så följer det oftast något som kallas cdata, det står för character data, och sedan kommer en sluttag, t.ex. </book>, eller en ny tag. I sgml så kan man ibland utelämna taggar om det av sammanhanget klart framgår vad som menas, denna funktion 9.1 är avslagen i DocBook. Det vill säga att varje element består av ett tagpar (logiskt eller uttryckligen), cdata och andra element.
I SGML kan man också skriva kommentarer som inte tolkas av SGML översättaren. Dessa skrivs som <!- lite text ->
Strukturen i DocBook går från att man har ett <set> med <book> och varje <book> innehåller ett eller flera kapitel. Det finns även andra huvudtyper av dokument som article, refset.
En normal DocBook bok har en struktur som påminner om följande:
Book Bookinfo ToC <!-- Table of contents --> LoT <!-- För bilder --> LoT <!-- För tabeller --> Preface Chapter Chapter Chapter Reference Appendix Appendix Glossary Bibliography Index
Som sagt så är <book> det högsta elementet i en bok. Detta element har attribut som kan sättas till olika värden. Ett mycket använt attribut är lang="svse" detta skrivs <book lang="svse"> och bestämmer att detta är ett dokument som är skrivet på Svenska. Andra attribut som kan vara värda att lägga på minnet är id="textsträng" och role="textsträng", id används för att namnge en del av dokumentet så att man kan referera till den och om man behöver använda en tag på ett sätt den inte är avsedd för använder man role.
I DocBook finns två typer av semantiska element, de som är hirarkiska till sin funktion, och de som är till för att göra logiska block. Det är viktigt att skilja på dessa. Skilnaden är t.ex. en paragraf är ett logiskt block som kan förekomma på många ställen i hirarkin medans en sektion bara kan förekomma i ett kapitel.
<bookinfo></bookinfo> används för att förse dokumentet med information
om författare, publicering, tryckning och upphovsrätt. I kort allt det som
gäller
boken och som brukar tryckas på insidan av första bladet. Saker som kan vara
bra att fylla i är <author></author> som i sin tur innehåller
<honorific></honorific>, <firstname></firstname>,
<othername></othername>
och <lineage></lineage> vilka innehåller den sedvanliga författar
informationen som namn. Honorific motsvarar svenskans akademisk titel,
lineage används knappast i Sverige, men skall innehålla tert som jr, dä, dy
för att särskilja två författare som har samma namn. Förutom detta så finns
också <authorblurb></aurthorblurb> som innehåller lite lös text om
författaren innom <para> taggar.
<leagalnotice></leagalnotice> är också bra att känna till den används för att kunna skriva saker som, detta dokument får inte reproduceras. För att indikera vem som har upphovsrätt på verket används <copyright>.
<COPYRIGHT> <YEAR>1998</YEAR> <HOLDER>Martin Wahlen</HOLDER> </COPYRIGHT> <LEGALNOTICE> <PARA> Detta är ett exempel på Copyright som man kan använda! </PARA> </LEGALNOTICE>
Är ett kort exempel på vad en bookinfo kan innehålla.
<toc></toc> Insättningspunkt för en innehållsförteckning. Här genereras en innehållsförteckning med alla Kapitel, Sektioner och Appendix.
Dessa element är uppradade eftersom de utgör själva innehållet i de flesta dokument. Under dessa kan man ha ett antal sektioner. Eller så kan man bara ha lösa paragrafer om man vill det.Elementen skall alltid ha minst en rubrik. Rubriken skrivs innom <title> taggar och är ett logisktblock. Det vill säga att man inte behöver skriva <para></para> runt den text man vill ha som rubrik.
<chapter id="kapitel1"> <title>Hej</title> <para>Detta är ok</para> </chapter>
Här införde vi ä detta motsvarar ett ä, eftersom man inte kan vara säker på att alla datorer hanterar 8-bitars tecken uppsättning har man valt att låta SGML koda vissa bokstäver som entities. De som används på svenska är å, ä och ö. Det är även bra att kunna danskans ä nämligen &aeling;.
Det finns många olika typer av listor i DocBook, men gemensamt har de alla att <listitem><para>Text</para></listitem> är hur listorna är uppbyggda. De två vanligaste typerna av listor är <OrderedList> och ItemizedList.
Något som brukar vara ganska populärt när man skriver dokument är figurer och bilder som illustrerar det man diskuterar. I DocBook så används <figure> för detta ändamål. <figure> har ett par viktiga extra attribut, det viktigaste är float, detta attribut har två värden ett eller noll. Ett gör att figuren kan flyttas i texten till det ställe där JADE tycker att den passar bäst. Noll innebär att bilden måste sättas in här i förhållande till texten. I figuren skall det sedan stå en <title> tag med en beskrivande rubrik till bilden.
Efter <title> taggarna kommer det som är intressant nämligen <graphic> taggen. Den har som attribut fileref="filnamn" vilket gör att man kan ta in bilder i sina dokument. Vidare så finns ett attribut, format="format" där format kan vara eps, gif, jpeg, etc
DocBook använder sig av CALS tabeller. Detta är en typ av tabell som finns med i många olika dokumenttyper. En tabell är ju troligen något som inte är så olikt oavsätt vilken typ av dokument man skriver.
CALS tabellen
Man kan ju givetvis generera ett index till sina böcker och skrifter det finns ett flertal taggar för att göra detta. Normalt så använder man
<!DOCTYPE article PUBLIC "-//Davenport//DTD DocBook V3.0//EN" [ ]> <article lang="svse" id="Exempel1"> <artheader> <author> <firstname>Martin</firstname> <surname>Wahlen</surname> <othername>Viktor</othername> <authorblurb> <para>Styrelseledamot i SSLUG och studerande vid Lunds Universitet</para> </authorblurb> </author> <abstract> <para> Detta är en artikel som visar lite olika finesser i DocBook och i SGML. </para> </abstract> </artheader> <sect1> <title>Ett logisktblock är rubriken</title> <para> För att skriva i DocBook behöver man en bra editor. T.ex. VIM (VI Improved). Andra alternativ är emacs med psgml, jed eller någon av de kommerciella alternativen som FrameMaker+SGML. </para> <itemizedlist id="not-in-para"> <listitem><para>Detta är en lista</para></listitem> <listitem><para>Här kan man ha saker</para></listitem> <listitem><para>En listitem kan innehålla flera paragrafer</para> <para>Som den här</para> </listitem> <listitem> <orderedlist> <listitem><para>Inne i Listan så kan man ha en lista till!<para></listitem> </orderedlist> </listitem> </itemizedlist> <para> En lös paragraf kan följa efter listan. Och den kan ha en lista i sin tur <itemizedlist id="in-para"> <listitem><para> Litetext </para></listitem> </itemizedlist> </para> </sect1> </article>
För att få ännu lite mer förståelse för fördelarna med SGML och att skriva
i SGML behöver man lite mer praktiska tips. Innan så nämde vi
<!DOCTYPE book PUBLIC "-//Davenport//
DTD DocBook V3.0//EN" []> och
att man kunde utöka dokument typen genom att skriva till saker innom
[] en av de saker som är bra att skriva där är
<!ENTITY
för mitt namn. Ni kan säkert hitta på fler intersanta användningsområden.
För detta. En annan intersant sak är markerade sektioner genom att skriva
<[IGNORE[
Lite text
]]>
så kan man få SGML översättaren att ignorera stycken. Om man kombinerar detta
med det faktum att man kan sätta in ENTITY nykelord i texten så kan man göra
mycket modulära dokument. T.ex. så kan man skriva sin CV så att den innehåller
alla projekt man har arbetat på och med hjälp av markerade sektioner så kan
man aktivera de sektioner som är viktiga för just ett visst arbete.
Jag rekomenderar att ni även tittar på SGMLtools hemsidan på http://www.sgmltools.org och på DocBook hemsidan http://www.ora.com/davenport
I grep och flera andra UNIX-program används något som kallas för reguljära mönster. Syftet med reguljära mönster är helt enkelt att matcha text. Tekniken liknar den som skalet använder för att matcha filnamn, men den är mycket kraftfullare. De följande sidorna beskriver hur reguljära mönster byggs upp.
Reguljära mönster kan innehålla flera symboler,
metatecken, som har speciella betydelser.
Metatecknen är . \ * [ ^ och $.
Det enklaste av dem är punkten.
Den matchar ett godtyckligt tecken.
(Dock med undantag för nyrad-tecknet.
Då grep och andra program
som använder reguljära mönster endast
betraktar en rad i taget,
kan mönstren aldrig innehålla något nyrad-tecken.)$ grep 'n.ta' bellman
den skönsta nymf, som åt dig ler,
inunder armen tag.
$Mönstret n.ta matchade här ''nsta'' och ''n ta''.
Om mönstret innehåller flera punkter så matchar varje
punkt ett godtyckligt tecken; det behöver inte vara samma
tecken varje gång:$ grep 'n..a' bellman
från Bacchi buller och tumult,
och du, du yngling, lyd min lag:
den skönsta nymf, som åt dig ler,
inunder armen tag.
$Genast undrar man hur man ska kunna matcha en punkt.
Svaret är att såväl punkten som de övriga metatecknen skyddas av
det bakvända snedstrecket:$ grep 'tag\.' bellman
inunder armen tag.
$Om vi utelämnar skyddet för punkten, så matchar den
bla blanktecken:$ grep 'tag.' bellman
inunder armen tag.
nå välan, så tag dig då en sup,
tag dig se'n dito en, dito två, dito tre,
$Mycket ofta måste man skydda reguljära
mönster eftersom de kan innehålla
symboler som har en speciell betydelse för skalet.
Tex måste mönstret tag\. skyddas för att
skalet inte ska plocka bort det bakvända snedstrecket.
Vi kommer därför konsekvent att använda apostrofer
som beskydd för mönstret,
även när det som i fallen n..a och
tag. ovan inte är strängt nödvändigt.
Om vi vill matcha en apostrof tvingas vi dock göra så här:$ grep \' bellman
tag dig se'n dito en, dito två, dito tre,
$
Reguljära mönster använder hakparenteser för att matcha en lista
av tecken. Lyckligtvis är syntaxen densamma som för
motsvarande jokertecken i skalet.
Mönstret [A-J] matchar alltså en av versalerna från A till J.$ grep '[A-J]' bellman
från Bacchi buller och tumult,
när döden ropar: Granne, kom,
Du gubbe, fäll din krycka ner,
$Nästa uppgift är att finna de rader i filen bellman
som innehåller någon stor bokstav. Detta är lätt,
vi kan helt enkelt använda mönstret [A-ZÅÄÖ].
Men det finns ett bättre sätt att ange alla stora bokstäver,
nämligen [:upper:].
(I tabell
ges en förteckning över
de kategorier av tecken som kan anges på liknande sätt.)
|
Om man sätter tecknet ^ direkt efter den vänstra
hakparentesen, så matchas ett godtyckligt
tecken som inte räknas upp i listan.
Så här finner vi de rader som innehåller texten ''du''
följt av något annat än kommatecken:$ grep 'du[^,]' bellman
och du, du yngling, lyd min lag:
så dör du nöjdare.
$Bara den första raden i filen bellman saknar såväl
punkt som kommatecken:$ grep -v '[.,]' bellman
Så lunka vi så småningom
$
Den minsta beståndsdelen i reguljära mönster,
som vi kan kalla för en ''atom'',
matchar exakt ett tecken.
Vi har redan beskrivit atomerna.
Tabell
ger en sammanfattning av dem.
|
.
Metatecknen $ och ^ matchar
början respektive slutet av en rad.
Så här finner vi alltså de rader som inleds
med ''och'':$ grep '^och' bellman lenngren
^ förankrar
mönstret till början av en rad.
Analogt förankrar dollartecknet ett mönster till
slutet av en rad.
Vilka rader slutar med tecknen ''an''?$ grep 'an$' bellman lenngren
bellman:från Bacchi buller och tumult,
lenngren:med klunk för klunk och bit för bit,
|
\< matchar början av ett ord.
Så här söker vi efter ord som börjar på ''dit'':$ grep '\<dit' bellman
Efter en atom kan man placera en ''multiplikator'', som
upprepar atomen ett antal gånger.
En förteckning av multiplikatorerna ges i
tabell
.
Metatecknet * betyder
att föregående atom får upprepas
hur många gånger som helst (inklusive noll).$ grep 'ul*t' bellman lenngren
bellman:från Bacchi buller och tumult,
bellman: ditt timglas är nu fullt.
lenngren:matt utstäckt mellan tvenne lakan.
$Mönstret ul*t matchade såväl ''ult'' som
''ullt'' och ''ut''.$ grep o.*st lenngren
Vår prost jag häromdagen såg
sig hävde upp mot isterhakan.
sin frukost redan färdig fann
$Mönstret o.*st matchade här ''ost'' och ''ot ist''.
Lägg märke till att .* matchar en godtycklig följd av tecken.
Vilka av de rader som innehåller
texten ''in'' slutar med ett kommatecken?$ grep 'in.*,$' bellman
Du gubbe, fäll din krycka ner,
$Vilka ord börjar med d och slutar med n?$ grep '\<d[[:alpha:]]*n\>' bellman
när döden ropar: Granne, kom,
Du gubbe, fäll din krycka ner,
den skönsta nymf, som åt dig ler,
$De ord som gav träff ovan var ''döden'', ''din'' och ''den''.
Multiplikatorn \? upprepar föregående atom noll eller
en gång:$ grep 'ul\?t' bellman lenngren
bellman:från Bacchi buller och tumult,
lenngren:matt utstäckt mellan tvenne lakan.
$Multiplikatorn \+ upprepar föregående atom en eller
fler gånger:$ grep 'ul\+t' bellman lenngren
bellman:från Bacchi buller och tumult,
bellman: ditt timglas är nu fullt.
$
Nu ska vi leta efter en följd av
små bokstäver som omges av ett ''n'' och ett ''e'':$ grep 'n[[:lower:]]*e' bellman
när döden ropar: Granne, kom,
Du gubbe, fäll din krycka ner,
inunder armen tag.
så dör du nöjdare.
$
|
\{ och \} ange
exakt hur många gånger atomen får upprepas.
Texten ''nunde'' ur ordet ''inunder'' består
av ett ''n'' följt av tre små bokstäver och ett ''e'':$ grep 'n[[:lower:]]\{3\}e' bellman
när döden ropar: Granne, kom,
Du gubbe, fäll din krycka ner,
när döden ropar: Granne, kom,
|
\|.
Det lodräta strecket \| betyder ''eller'', så
det totala mönstret matchar de textsträngar som matchas av något av
de alternativa mönstren.
Så här finner vi de rader som innehåller något av orden
''du'', ''dig'' eller ''ditt'':$ grep 'du\|dig\|ditt' bellman
och du, du yngling, lyd min lag:
den skönsta nymf, som åt dig ler,
Tycker du, att graven är för djup,
nå välan, så tag dig då en sup,
tag dig se'n dito en, dito två, dito tre,
\( och \).$ grep '\(du\|dig\|ditt\).*\<är\>' bellman
Tycker du, att graven är för djup,
Ett reguljärt mönster som omges av
tecknen \( och tecknen \)
kan behandlas som en atom. Därigenom blir
det möjligt att placera en multiplikator på mönstret.$ grep '\(du,\? \)\{2,\}' bellman
och du, du yngling, lyd min lag:
$
Den text som matchas av ett mönster
som omges av \( och \), sparas i ett så
kallat register. Man kan referera till texten
i registret med tecknen \1.
Så här finner vi de fall då a, b eller c
förekommer två gånger i rad:$ grep '\([abc]\)\1' bellman
från Bacchi buller och tumult,
Du gubbe, fäll din krycka ner,
$Ovan fick vi träff på ''cc'' i ordet ''Bacchi''
respektive ''bb'' i ordet ''gubbe''.
Finns det några ord som slutar med en dubblerad bokstav?$ grep '\([[:alpha:]]\)\1\>' bellman
ditt timglas är nu fullt.
Du gubbe, fäll din krycka ner,
Tycker du, att graven är för djup,
$Ja, ''ditt'', ''fäll'' och ''att''.
Om det förekommer flera par av tecknen \( och \)
i ett reguljärt mönster, så sparas den matchande texten i upp till
nio olika register. Den text som matchar mönstret i
parentesen längst till
vänster sparas i register 1. Register 2 hör till
parentesen näst längst till vänster osv.
Innehållet i register n matchas av \n.
Programmet sed är (bland annat) till för att automatisera textredigering. Det skapades genom en enkel bearbetning av editorn ed. Det läser in en text i form av indata eller från en fil, utför redigeringskommandon på en textrad i taget, och skriver sedan ut raden i sin nya form. Den ursprungliga filen ändras inte.
En av de redigeringar sed kan göra är substitutionen
''Byt söktext mot ersättningstext'';
det skrivs s/söktext/ersättningstext/.
Söktexten kan vara ett reguljärt mönster.
I stället för tecknet / kan man välja något annat
förutsatt att samma tecken används på alla tre ställen i kommandot.
Flaggan -e anger att nästa argument är ett kommando
till sed och inte ett filnamn.
Så här byter vi ut ''du'' mot ''DU'' i filen bellman:$ sed -e 's/du/DU/' bellman
Så lunka vi så småningom
från Bacchi buller och tumult,
när döden ropar: Granne, kom,
ditt timglas är nu fullt.
Du gubbe, fäll din krycka ner,
och DU, du yngling, lyd min lag:
den skönsta nymf, som åt dig ler,
inunder armen tag.
Tycker DU, att graven är för djup,
nå välan, så tag dig då en sup,
tag dig se'n dito en, dito två, dito tre,
så dör DU nöjdare.
$I utskriften har den första förekomsten av ''du'' på
varje rad bytts ut mot ''DU''.
Det är oftast nödvändigt att skydda redigeringskommandona med
apostrofer, så det är bra att göra det till en vana att alltid ha dem med.
Om alla förekomster
ska bytas ut, så ska man ange flaggan g i slutet
av substitutionskommandot:$ sed -e 's/[dD]u/DU/g' bellman
Så lunka vi så småningom
från Bacchi buller och tumult,
när döden ropar: Granne, kom,
ditt timglas är nu fullt.
DU gubbe, fäll din krycka ner,
och DU, DU yngling, lyd min lag:
den skönsta nymf, som åt dig ler,
inunder armen tag.
Tycker DU, att graven är för djup,
nå välan, så tag dig då en sup,
tag dig se'n dito en, dito två, dito tre,
så dör DU nöjdare.
$I stället för g kan man ange
ett nummer n, och då byts bara den n:te förekomsten
på varje rad ut.
Flaggan -n gör så att ingen rad automatiskt skrivs ut:$ sed -ne 's/[dD]u/DU/g' bellman
$Flaggan p i substitutionskommandot anger att de rader som
innehåller söktexten ska skrivas ut:$ sed -ne 's/[dD]u/DU/gp' bellman
DU gubbe, fäll din krycka ner,
och DU, DU yngling, lyd min lag:
Tycker DU, att graven är för djup,
så dör DU nöjdare.
$Tecknet & i ersättningstextentexten står för
det som matchas av söktexten.$ sed -ne 's/[dD]u/(&)/gp' bellman
(Du) gubbe, fäll din krycka ner,
och (du), (du) yngling, lyd min lag:
Tycker (du), att graven är för djup,
så dör (du) nöjdare.
$
Programmet åäö nedan ger ett typiskt exempel på hur sed används.
#!/bin/bash if [ $# -ne 1 ] ; then echo "Ange exakt ett argument" 1>&2 exit 1 fi if [ ! -f "$1" ] ; then echo "Filen $1 finns inte" 1>&2 exit 1 fi mv "$1" "$1.kopia" sed \ -e 's/å/\å/g' -e 's/ä/\ä/g' -e 's/ö/\ö/g' \ -e 's/Å/\å/g' -e 's/Ä/\Ä/g' -e 's/Ö/\Ö/g' \ "$1.kopia" > "$1"
Programmet tar ett argument, som ska vara
namnet på en fil.
Först kontrolleras det att antalet argument är 1.
Om inte, så avslutas programmet med ett näsvist
felmeddelande. Likaså avslutas programmet om argumentet
inte är namnet på en befintlig fil.
Filen kopieras sedan till en ny fil som
ges ett namn med ändelsen .kopia.
Sedan byts bokstäverna åäöÅÄÖ ut mot textsträngar
som motsvarar dem i språket HTML,
och resultatet sparas i en fil med samma namn som den
ursprungliga.
Lägg märke till att &-tecknen i ersättningstexten
måste skyddas.
Antag nu att det i katalogen /tmp
finns en HTML-fil:$ ls /tmp
test.html
$ cat /tmp/test.html
<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML//EN">
<html>
<head>
<title>Test av åäö</title>
</head>
<body>
<h1>Test av åäö</h1>
Det här är en testfil för
mitt lilla program "åäö"!
</body>
</html>
$Låt oss köra programmet på filen:$ åäö /tmp/test.html
$ ls /tmp
test.html test.html.kopia
$ cat /tmp/test.html
<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML//EN">
<html>
<head>
<title>Test av åäö</title>
</head>
<body>
<h1>Test av åäö</h1>
Det här är en testfil för
mitt lilla program "åäö"!
</body>
</html>
$Ett visst mått av felhantering finns i programmet:$ åäö bellmna
Filen bellmna finns inte
$ åäö bellman lenngren
Ange exakt ett argument
$
När ett program kört färdigt berättar det ifall körningen var lyckad eller misslyckad. Vad det innebär att körningen lyckats varierar från program till program, men oftast innebär ett misslyckande att någon form av fel uppstått. Så hur fungerar det hela? Jo, programmet lämnar ifrån sig ett tal, som kallas dess slutstatus, då det avslutas. Om talet är 0, så anses körningen vara lyckad. Om talet är större än 0, så anses körningen ha misslyckats. Tex kan slutstatus 1 markera en viss typ av fel och slutstatus 2 ett annat slags fel.
I Bash anger parametern ? slutstatus för
det senaste kommandot man gett.$ rm kopia.980217.bellmna
rm: kopia.980217.bellmna: Filen eller katalogen finns inte
$ echo $?
1
$ rm kopia.980217.bellman
$ echo $?
0
$Vid första rm-kommandot ovan uppstod ett fel,
och slutstatus var 1. Nästa gång gick det bra,
och slutstatus var 0.
Kommandot exit 0 avslutar ett Bashprogram med slutstatus 0. För att ge slutstatus 1 skriver man i stället exit 1 osv. Om siffran utelämnas, så avslutas programmet med samma slutstatus som det senast utförda kommandot.
Kommandot test kan undersöka olika slags
villkor. Om villkoret är uppfyllt
lämnar test slutstatus 0, annars
lämnas slutstatus 1. Tex kontrollerar test 5 -gt 7
ifall 5>7. Här står -gt för ''greater than''
(se tabell 11.4).
Som synonym för test kan man använda tecknet
[, och då skriver man
[ 5 -gt 7 ] istället.$ test 5 -gt 7
$ echo $?
1
$ test 7 -gt 5
$ echo $?
0
$ [ 1 -gt -2 ]
$ echo $?
0
$Detta innebär att villkoren 7>5 och 1>-2
är uppfyllda, men inte 5>7.
Med hjälp av en if-sats kan man få ett program att vidta olika åtgärder beroende på om ett villkor är uppfyllt eller inte. Syntaxen är
Först körs testkommando. Om det lyckades (dvs om det har slutstatus 0) så utförs kommandot kommando. Man kan ha fler radbrytningar om man vill, Bash vet att kommandot inte är komplett förrän man skrivit fi. Det är också möjligt att skriva kommandot på en rad, men då måste man använda semikolon i stället för radbrytning.$ if [ 5 -gt 7 ] ; then echo Hej ; fiiftestkommando
thenkommando
fi
Hej
Om man vill, så kan man ha raden ''else alternativkommando'' före fi ovan; i så fall utförs alternativkommando ifall testkommandot misslyckades. Dvs if kan användas så här också:
iftestkommando
thenkommando
elsealternativkommando
fi
Vi ändrar vårt program argument till följande:
#!/bin/bash
echo "Totalt $# argument."
if [ $# -gt 12 ] ; then
echo "Det trettonde argumentet är ${13}."
else
echo "Det finns inget trettonde argument." 1>&2
exit 1
fi
Om antalet argument är större än 12, så skrivs det trettonde
argumentet ut.
Annars skrivs ett felmeddelande ut och
programmet avslutas med slutstatus 1.$ argument a b c d e f g h i j k l m n o p q r
Totalt 18 argument.
Det trettonde argumentet är m.
$ echo $?
0
$ argument esike desike luntan tuntan
Totalt 4 argument.
Det finns inget trettonde argument.
$ echo $?
1
$
I tabellerna 11.1, 11.2, 11.3,
11.4 och
11.5 ges en förteckning av de viktigaste
testerna som test eller [
kan utföra.
|
|
|
|
|
Bash kan skilja mellan olika fall beroende på värdet av en variabel med hjälp av kommandot case. Programmet genus nedan ger ett exempel.
#!/bin/bash case $1 in Anna | Eva | Åsa) echo "$1 är en kvinna." ;; Kalle | Nisse | Pelle) echo "$1 är en man." ;; * ) echo "Jag vet inte huruvida $1 är en kvinna eller en man." ;; esac
Så här fungerar programmet:$ genus Eva
Eva är en kvinna.
$ genus Nisse
Nisse är en man.
$ genus Sofia
Jag vet inte huruvida Sofia är en kvinna eller en man.
$ Syntaxen för kommandot case är
Mellancaseordin
val|val ...|val)kommandon ;;
val|val ...|val)kommandon ;;
...
esac
case och esac (som är ''case'' baklänges,
liksom ''fi'' är ''if'' baklänges) anges ett eller flera fall,
separerade av dubbla semikolon.
I varje sådant fall får man ange ett eller flera val,
separerade av lodräta streck, samt därefter en högerparentes
och ett godtyckligt antal kommandon som ska utföras
ifall ord är något av dessa val.
Bara kommandona från det första fallet där ord förekommer
utförs. Liksom filnamn får valen innehålla jokertecken.
Det är därför som valet * i programmet
genus matchar allt som inte matchas av
något av de andra valen.
Ofta vill man att ett kommando ska utföras flera gånger beroende på vissa villkor. Bash erbjuder några olika möjligheter till sådana upprepningar. Ett alternativ är for, vars syntax ser ut så här:
(Man får som vanligt använda semikolon i stället för radbrytning.) För varje argument i argumentlista antar variabeln variabel detta argument som värde under det att kommando utförs. Här är ett exempel:$ for i in esike desike luntan tuntanforvariabelinargumentlista
dokommando
done
> do echo "Nu har 'i' värdet $i"
> done
Nu har 'i' värdet esike
Nu har 'i' värdet desike
Nu har 'i' värdet luntan
Nu har 'i' värdet tuntan
Vill man att variabel ska genomlöpa en
följd av tal, så kan man låta
seq generera talföljden.
Instruktionen seq 5 skriver ut talen från 1 till 5,
separerade av nyrad-tecken:$ seq 5
1
2
3
4
5
$ Men hjälp av flaggan -s kan man ange en annan separator:$ seq -s '+' 5
1+2+3+4+5
$ Följden behöver inte börja på 1:$ seq -s ' ' 3 12
3 4 5 6 7 8 9 10 11 12
$ Så här genereras vart sjunde tal mellan 2 och 50:$ seq -s ',' 2 7 50
2,9,16,23,30,37,44
$ Vi använder nu seq i en for-sats:$ ls
Kapitel40A/ bellman lenngren
$ for i in $(seq 4) ; do cp bellman epistel$i.text ; done
$ ls
Kapitel40A/ epistel1.text epistel3.text lenngren
bellman epistel2.text epistel4.text
$Filen bellman kopierades till fyra nya filer.
Innan for-satsen utfördes skrevs
$(seq 4) om till talen från 1 till 4,
se avsnitt 6.5.
(Skalet åt upp de nyrad-tecken som genererades av seq,
se
.)
När man använder
for-satser i Bash-program vill man ofta
att variabeln ska genomlöpa varje argument
programmet anropades med.
Om ''in text'' utelämnas, så
sker just detta.
Vi ger nu ett program som kopierar var och en av
de filer man anger som argument.
#!/bin/bash for FIL do cp $FIL $FIL.kopia done
Vi antar att programmet heter kopiera.$ kopiera epistel[3-5].text
$ ls
Kapitel40A/ epistel2.text epistel4.text
bellman epistel3.text epistel4.text.kopia
epistel1.text epistel3.text.kopia lenngren
$ Ovan har vi använt jokertecken för att matcha två
filnamn, som blir argument till programmet
kopiera. I programmet genomlöper variabeln
FIL de båda filnamnen.
Lägg märke till att det är Bash som tar hand om jokertecknen,
vårt program har ingen aning om deras existens!
Ett annat sätt att upprepa kommandon är while-satsen. Dess syntax är
Först körs testkommando. Om det lyckades, så körs kommando och därefter upprepas det hela. Om testkommando misslyckas, dvs om dess slutstatus är skild från 0, så körs inte kommando utan programmet fortsätter efter done.whiletestkommando
dokommando
done
En variant av while är until. Dess syntax är
Här körs först testkommando. Om det misslyckas, så körs kommando och det hela upprepas. Om testkommando lyckas, så avslutas until och programmet fortsätter efter done.untiltestkommando
dokommando
done
Som testkommando i if-, until- och while-konstruktioner kan man ta vilket kommando som helst, det behöver inte vara test. Testet betraktas som uppfyllt om programkörningen lyckades, dvs om dess slutstatus är 0. För tex grep är körningen lyckad om söktexten påträffades, annars misslyckad. Här är ett exempel:
#!/bin/bash if grep rätt $1 ; then echo Ordet \"rätt\" finns i filen $1 else echo Ordet \"rätt\" finns inte i filen $1 fi
Programmet undersöker om ordet ''rätt'' finns i en
fil vars namn anges med ett argument.$ leta bellman
Ordet "rätt" finns inte i filen bellman
$ leta lenngren
och fann likören rätt begärlig.
Ordet "rätt" finns i filen lenngren
$ Ifall man vill slippa utskriften kan man skicka den
till /dev/null; då raderas den helt enkelt.
Men i det här fallet är det enklare att ge grep flaggan
-q, som anger att man inte vill ha någon utskrift.
Härnäst vill vi köra en fil genom programmet LATEX upprepade gånger tills filen är färdigbehandlad. LATEX skriver ut texten ''Rerun to get cross-references right.'' ifall filen måste köras igen. Följande program löser problemet:
#!/bin/bash echo 'Kör LaTeX...' while latex gnulinux.tex | grep 'Rerun to get cross-references right.' do echo 'OK, kör LaTeX igen...' done
Slutstatus för en rörledning är lika med det sista kommandots slutstatus, så villkoret i while-kommandot ovan är uppfyllt om grep finner den sökta texten.
Om man ger två kommandon separerade av &&,
så utförs det andra kommandot om och endast om det
första lyckades.
Om kommandona istället separeras av ||,
så utförs det andra kommandot om och endast om det
första misslyckades.
Motsvarande funktionalitet kan lätt fås med hjälp
av if-satser, men ibland blir dessa konstruktioner
mer lättlästa.$ [ -x /bin/date ] && echo Ja
Ja
$ [ -x bellman ] && echo Ja
$ grep Gnu bellman || echo 'Ordet Gnu finns inte i filen'
Ordet Gnu finns inte i filen
$ [ 7 -gt 43 ] && echo Större || echo Mindre
Mindre
$ Det första kommandot ovan undersöker ifall
/bin/date är ett körbart program,
och skriver i så fall ut ordet ''Ja''.
Det andra kommandot gör motsvarande
med filen bellman, som dock inte
är ett körbart program.
Det tredje kommandot söker först efter ordet
''Gnu'' i filen bellman, och eftersom
sökningen misslyckades utfördes kommandot
echo som skrev ut ett meddelande.
Det sista kommandot visar en motsvarighet till
if-then-else.
Det finns ännu en variant av if:
efter then kommando,
och före ett eventuellt else,
kan man en eller flera gånger ha konstruktionen
Här är elif ungefär en sammanslagning av else if. Om föregående testkommando misslyckades, så körs nyttestkommando. Ifall detta lyckas, så körs nyttkommando och if-satsen avslutas; annars hoppas nyttkommando över och programmet fortsätter vid nästa elif eller else (om det förekommer något sådant före fi). Ett exempel:elifnyttestkommando
thennyttkommando
#!/bin/bash if [ $1 -lt 0 ] ; then echo 'Talet är negativt!' elif [ $1 -lt 10 ] ; then echo 'Talet är ensiffrigt.' elif [ $1 -lt 100 ] ; then echo 'Talet är tvåsiffrigt.' else echo 'Talet har fler än två siffror.' fi
Programmet tar ett heltal som argument,
och svarar att talet är negativt eller att det
har en, två eller fler siffror.
Så här fungerar programmet:$ iftest 43
Talet är tvåsiffrigt.
$ iftest -3
Talet är negativt!
$ iftest 32521
Talet har fler än två siffror.
$ iftest 0
Talet är ensiffrigt.
$
Vi ska nu skriva ett program som raderar filer. Programmet ska fråga efter bekräftelse för varje fil. I programmet använder vi Bashkommandona break och continue. Det förra får Bash att hoppa till kommandot efter done i en while-konstruktion, det senare får Bash att hoppa till kommandot done (men inte förbi det). Så här ser programmet radera ut:
#!/bin/bash
while [ $# -ne 0 ] ; do
read -p "Radera $1 (j/n/s)? " SVAR
case "$SVAR" in
[Jj] | [Jj]a | JA) rm "$1" ;;
[Nn] | [Nn]ej | NEJ) ;;
[Ss]) break ;;
*) echo 'Felaktigt svar, försök igen!' ; continue ;;
esac
shift
done
Låt oss prova programmet innan vi tittar närmare på det.$ ls
Kapitel40A/ epistel2.text epistel4.text
bellman epistel3.text epistel4.text.kopia
epistel1.text epistel3.text.kopia lenngren
$ radera epistel*
Radera epistel1.text (j/n/s)? j
Radera epistel2.text (j/n/s)? nej
Radera epistel3.text (j/n/s)? nja
Felaktigt svar, försök igen!
Radera epistel3.text (j/n/s)? Ja
Radera epistel3.text.kopia (j/n/s)? ja
Radera epistel4.text (j/n/s)? s
$ ls
Kapitel40A/ epistel2.text epistel4.text.kopia
bellman epistel4.text lenngren
$ För varje fil har man tre val: att radera den,
att inte radera den samt att avsluta.
Om man skriver j
(eller J eller ja eller Ja eller JA),
så raderas filen.
Om man skriver s eller S, så
utförs kommandot break som får Bash att hoppa
till efter done varvid programmet avslutas.
Om man skriver ett ogiltigt svar, så får
kommandot continue Bash att gå tillbaka till do
utan att shift utförs, och man får då
en ny fråga om samma fil.
Man kan använda break och
continue i for-satser,
som följande exempel visar:$ cat exempel
#!/bin/bash
for i in $(seq 10 -1 1)
do
[ $i -eq 8 ] && continue
echo "Nu har 'i' värdet $i"
[ $i -eq 6 ] && break
done
$ exempel
Nu har 'i' värdet 10
Nu har 'i' värdet 9
Nu har 'i' värdet 7
Nu har 'i' värdet 6
$
Om man använder kommandot shift i ett
Bashprogram, så tas det första
argumentet bort.
Det som förut var $2 blir då $1,
det som var $3 blir $2 osv.
Samtidigt minskar $# med ett.
Kommandot shift 2 har samma verkan som två stycken
shift. Dvs $# minskar med två,
det som var $3 blir $1,
det som var $4 blir $2 osv.
På motsvarande sätt fungerar shift 3,
shift 4 osv.
Följande program, som helt enkelt anger alla sina argument, ger ett exempel på hur shift kan användas.
#!/bin/bash echo "Totalt $# argument." while [ $# -gt 0 ] do echo "Ett argument är $1." shift done
Genom att köra programmet ovan några gånger ska
vi demonstrera hur Bash hanterar argumenten.
Vi minns sedan avsnitt 3.4
att oskyddade blank- och nyradtecken separerar argument.$ allaargument ole 'dole doff'
Totalt 2 argument.
Ett argument är ole.
Ett argument är dole doff.
$ allaargument "Hej och hå"
Totalt 1 argument.
Ett argument är Hej och hå.
$ Med hjälp av citationstecken kan man till och med
ange den tomma textsträngen som ett argument.$ allaargument Ett tomt "" argument
Totalt 4 argument.
Ett argument är Ett.
Ett argument är tomt.
Ett argument är .
Ett argument är argument.
$ Separationen av argument sker efter eventuella
omskrivningar (med undantag för jokeromskrivningar):$ NAMN="Göran Andersson"
$ allaargument namnet är $NAMN
Totalt 4 argument.
Ett argument är namnet.
Ett argument är är.
Ett argument är Göran.
Ett argument är Andersson.
$ Ovan skrevs $NAMN om till Göran Andersson,
vilket räknas som två skilda argument.
Om variabeln namn inte har getts något värde, så
skrivs $namn om till en tom textsträng.
Därför räknas $ODEFINIERAD som
noll argument i följande exempel:$ allaargument Värdet är $ODEFINIERAD
Totalt 2 argument.
Ett argument är Värdet.
Ett argument är är.
$Ibland är detta tvärtemot vad man vill.
Hur får man Bash att uppfatta uttrycket
$variabel som exakt ett argument
även efter omskrivningen? Genom att
omge det med citationstecken!$ allaargument namnet är "$NAMN"
Totalt 3 argument.
Ett argument är namnet.
Ett argument är är.
Ett argument är Göran Andersson.
$ allaargument Värdet är "$ODEFINIERAD"
Totalt 3 argument.
Ett argument är Värdet.
Ett argument är är.
Ett argument är .
$
Om man slarvar vid hanteringen av argument, så kan man råka ut för märkliga spratt. Betrakta tex följande program, leta2:
#!/bin/bash if grep -q $1 $2 ; then echo 'Ja, texten finns i filen.' else echo 'Nej, texten finns inte i filen.' fi
Det första argumentet ska vara en text, det andra ett filnamn. Programmet har till uppgift att ta reda på om texten finns i den angivna filen. Vi har gett grep flaggan -q för att slippa dess utskrift. Antag att filen textfil har följande innehåll:
Det första argumentet ska vara en text, det andra ett filnamn. Programmet har till uppgift att ta reda på om texten finns i den angivna filen.Så här kan det gå när vi kör programmet leta2:$ leta2 'finns inte' textfil
För att rätta till felet måste vi se till att
grep betraktar värdet av $1 som
exakt ett ord. Vi omger därför $1
med citationstecken.
Hur går det om det andra argumentet, filnamnet,
innehåller ett mellanslag? Dåligt. Värdet av $2
betraktas då av grep som flera filnamn,
och programmet gör fel.
Så här ska det se ut i stället:$ cat leta3
#!/bin/bash
if grep -q "$1" "$2" ; then
echo 'Ja, texten finns i filen.'
else
echo 'Nej, texten finns inte i filen.'
fi
$ cp textfil 'konstig fil'
$ leta3 finns 'konstig fil'
Ja, texten finns i filen.
$ leta3 'finns inte' 'konstig fil'
Nej, texten finns inte i filen.
$
Antag nu att vi vill skriva om leta3
så att det kan söka efter en viss text i
flera olika filer. Dvs det första argumentet
ska vara söktexten, de övriga ska vara filnamn.
Då ska grep-kommandot ändras till
grep -q "$1" "$2" "$3" ifall man anger två filnamn,
till grep -q "$1" "$2" "$3" "$4" ifall man anger tre
osv. Hur ska det gå till när vi inte vet hur många
argumenten är?
Bash tolkar $* som
$1 $2 $3 osv fram till sista argumentet,
men det duger inte här eftersom argumenten
kan innehålla mellanslag.
Istället ska vi använda parametern @.
Den har samma värde som * utom när den
omges av citationstecken:
"$@" tolkas som
"$1" "$2" "$3" osv, vilket är just vad
vi behöver. Kommandot ska alltså skrivas
grep -q "$@".
Vi använder följande program för att belysa diskussionen ovan:
#!/bin/bash echo "Jag fick $# argument, men..." allaargument $* allaargument "$*" allaargument "$@"
Så här går det när vi kör programmet:$ argumenttest ole 'dole doff'
Jag fick 2 argument, men...
Totalt 3 argument.
Ett argument är ole.
Ett argument är dole.
Ett argument är doff.
Totalt 1 argument.
Ett argument är ole dole doff.
Totalt 2 argument.
Ett argument är ole.
Ett argument är dole doff.
$Programmet
allaargument anropades tre gånger.
Varje gång vidarebefordrades argumenten,
fast det skedde på olika sätt.
Först vidarebefordrades de som
ole dole doff (allaargument
fick då tre argument), sedan som
"ole dole doff" (allaargument
fick då ett argument) och till sist som
"ole" "dole doff" (vilket gav
två argument).
Det är bara "$@" som bevarar argumenten
precis som de var.
Man kan inte ge tex parametern 1 ett nytt värde genom en direkt tilldelning som om det varit en vanlig variabel. Däremot kan ett program ge sig själv de nya argumenten argument med kommandot set argument. Följande program använder set:
#!/bin/bash allaargument "$@" set Många "nya, fina" argument allaargument "$@"
Låt oss prova programmet!$ argumenttest2 hejsan svejsan
Totalt 2 argument.
Ett argument är hejsan.
Ett argument är svejsan.
Totalt 3 argument.
Ett argument är Många.
Ett argument är nya, fina.
Ett argument är argument.
$
Programmet filinformation nedan använder set på ett intressantare sätt:
#!/bin/bash set $(wc "$1") echo "Filen $4 har $1 rader och är $3 byte lång."
Som argument ska man ange ett filnamn.
Programmet talar om hur många rader och tecken
filen innehåller.$ wc /etc/passwd
30 42 1291 /etc/passwd
$ filinformation /etc/passwd
Filen /etc/passwd har 30 rader och är 1291 byte lång.
$ Utskriften från wc $1 har fyra delar:
först antal rader, sedan antal ord respektive tecken
och till sist filnamnet. Dessa fyra delar sätts
som argument, så att de kan plockas ut med
$1, $2 osv.
Som bekant erhålls värdet av variabel
då man skriver ${variabel}.
Vi ska nu beskriva ett antal strängoperatorer
som kan manipulera de värden som erhålls.
Uttrycket
${variabel:-sträng}
skrivs om till värdet av variabel
om det är definierat och inte tomt, annars till sträng.
På detta sätt kan man ha ett värde i reserv
när en variabel saknar värde.$ KAND=hej
$ echo ${KAND:-adjö}
hej
$ echo ${OKAND:-adjö}
adjö
$Reservvärdet adjö användes vid det andra tillfället ovan
eftersom variabeln OKAND är odefinierad.
Operatorn :- förändrar inte variabelns ursprungliga värde:$ echo $OKAND,$KAND
,hej
$Operatorn := fungerar som :- bortsett från att
variabeln variabel sätts lika med sträng ifall
den saknar värde.$ echo ${KAND:=adjö}
hej
$ echo ${OKAND:=adjö}
adjö
$ echo $OKAND,$KAND
adjö,hej
$
Uttrycket
${variabel:?sträng}
skrivs om till värdet av variabel
om det är definierat och inte tomt, annars
skrivs sträng ut som ett felmeddelande
(och programkörningen avbryts om detta inträffar i
ett program).$ echo "Säg ${KAND:?Värde saknas} till Göran."
Säg hej till Göran.
$ OKAND=
$ echo "Säg ${OKAND:?Värde saknas} till Göran."
bash: OKAND: Värde saknas
$
Uttrycket
${variabel:+sträng}
tas bort ifall variabel saknar värde,
annars skrivs det om till sträng:$ echo "Värdet är ${KAND:+inte }tomt."
Värdet är inte tomt.
$ echo "Värdet är ${OKAND:+inte }tomt."
Värdet är tomt.
$
För var och en av operatorerna :-, :=, :?
och :+ finns en motsvarande operator som skrivs
utan kolon. Dessa operatorer undersöker bara om variabeln
är odefinierad, inte om värdet är tomt.$ echo "Variabeln är ${OKAND+inte }odefinierad."
Variabeln är inte odefinierad.
$ echo "Variabeln är ${ODEFINIERAD+inte }odefinierad."
Variabeln är odefinierad.
$Ovan är variabeln OKAND definierad (dess värde är den tomma
strängen), medan variabeln ODEFINIERAD inte är definierad.
Uttrycket
${#variabel}
skrivs om till antalet tecken i värdet av variabel.$ ORD=skalprogrammering
$ echo ${#ORD}
17
$
Uttrycket
${variabel: n}
skrivs om till värdet av variabel men med de
första n tecknen borttagna:$ echo ${ORD: 4}
programmering
$Så här anger man att man vill behålla högst sju respektive
högst 20 stycken tecken:$ echo ${ORD: 4: 7}
program
$ echo ${ORD: 4: 20}
programmering
$Så här väljer vi ut de fyra sista tecknen:$ echo ${ORD: -4}
ring
$Blanktecknet före talet -4 är viktigt,
för annars skulle det förväxlas med operatorn :-.$ echo ${ORD:-4}
skalprogrammering
$Härnäst vill vi behålla högst tre av de sex sista tecknen
i värdet av variabeln ORD:$ echo ${ORD: -6: 3}
mer
$
Uttrycket
${variabel/mönster/sträng}
skrivs om till värdet av variabel men med den första,
längsta möjliga förekomsten av mönster utbytt mot
sträng. Här tolkas mönster som ett mönster precis
som när Bash matchar filnamn.
I följande exempel byter vi ut den första förekomsten av a
mot A:$ echo ${ORD/a/A}
skAlprogrammering
$Uttrycket
${variabel//mönster/sträng}
fungerar som det ovan bortsett från att varje förekomst av
mönster byts mot sträng.
Så här kan vi alltså ta bort alla vokaler:$ echo ${ORD//[aouåeiyäö]/}
sklprgrmmrng
$
Uttrycket
${variabel#mönster}
innebär att den
kortaste möjliga förekomsten av mönster i början
av värdet av variabel ska tas bort.
Så här stryker vi allt fram till det första blanktecknet:$ MENING='Hej, jag heter Göran!'
$ echo ${MENING#* }
jag heter Göran!
$Operatorn ## fungerar som # bortsett från att det
i stället är den längsta möjliga förekomsten av mönster
som tas bort:$ echo ${MENING##* }
Göran!
$Operatorerna % och %% fungerar som
# respektive ## bortsett från att man stryker
från slutet i stället. Så här kan man alltså byta
ändelsen i ett filnamn:$ FIL=uppsats.tex
$ echo ${FIL%.*}.dvi
uppsats.dvi
$Så här stryker vi allt som kommer efter det inledande decimaltalet:$ FORMEL=3.14+1.41-2.72
$ echo ${FORMEL%%[^0-9.]*}
3.14
$
Ordet ''aritmetik'' betyder helt enkelt räkning. I detta avsnitt beskrivs det hur man kan utföra enklare beräkningar med hjälp av Bash.
Ett uttryck av formen $((formel))
skrivs om till det uträknade värdet av formel.
Formlerna som beräknas får bland annat innehålla
de fyra vanliga räknesätten, som skrivs med operatorerna
+ (addition), - (subtraktion),
* (multiplikation) och / (division).$ echo $((17+23))
40
$ mkdir Kapitel$((17+23))A
$ ls
Kapitel40A/ kopia.980217.bellman
bellman lenngren
$Ingen beräkning sker ifall tecknen $(( och )) utelämnas:$ echo 17+23
17+23
$Man får också använda variabler:$ x=17; y=23
$ echo $((x+y))
40
$Lägg märke till att man inte behöver skriva dollartecken
före variablernas namn när de som ovan förekommer i en beräkning.
Med hjälp av while kan man låta en variabel genomlöpa en följd av tal, som programmet loop nedan visar.
#!/bin/bash i=5 while [ $i -le 10 ] do echo "Nu har 'i' värdet $i" i=$((i+1)) done
Utskriften från loop ser ut så här:$ loop
Nu har 'i' värdet 5
Nu har 'i' värdet 6
Nu har 'i' värdet 7
Nu har 'i' värdet 8
Nu har 'i' värdet 9
Nu har 'i' värdet 10
$
Multiplikationen i formeln
2+3*4
utförs före additionen eftersom
det är en konvention att multiplikation och division
har högre prioritet än addition och subtraktion.
Om man vill att additionen ska utföras först måste man ange parenteser,
(2+3)*4=20.$ echo Man räknar lätt ut att 2+3*4=$((2+3*4))
Man räknar lätt ut att 2+3*4=14
$ echo $(( (2+3)*4 ))
20
$
En förteckning av de operatorer som kan användas vid beräkningar i Bash ges i tabell 11.6. Operatorerna är grupperade i prioritetsordning.
|
Bash räknar bara med heltal.
Detta innebär i synnerhet att om resultatet vid en division inte
går jämnt ut, så stryks decimalerna från svaret.
Till exempel gäller i Bash att 13/5 är lika med 2.
Om 13 hästar ska delas ut till fem systrar,
så får systrarna två hästar var.
Kvoten är därmed 2. Det blir tre hästar över,
och man säger att resten
(dvs det antal som blev över) är 3.$ echo $(( 13/5 ))
2
$Resten vid en division kan beräknas med hjälp av operatorn %.$ echo $(( 13%5 ))
3
$
Bash kan bara hantera heltal av en begränsad storlek;
vanligtvis får talen ha högst
9-10 siffror om resultatet ska bli rätt.$ echo $(( 1000*1000 ))
1000000
$ echo $(( 1000000*1000000 ))
-727379968
$Det korrekta resultatet vid den andra beräkningen
ovan är ett tal med 13 siffror,
men eftersom Bash (på min dator) inte kan hantera så stora tal
gavs ett fullständigt felaktigt resultat.
Om man omger ett heltal med tecknen (( respektive )),
så undersöker Bash ifall talet är skilt från noll. Lyckad slutstatus
anger att talet var skilt
från noll, misslyckad slutstatus att talet var lika med noll.$ (( 5 ))
$ echo $?
0
$ (( 2*3-6 ))
$ echo $?
1
$ Som vi snart ska se kan detta användas som ett
alternativ till kommandot test vid jämförelser av heltal.
|
Tabell 11.7 visar hur man kan jämföra två heltal i Bash.
Lägg särskilt märke till att likhet skrivs med två
likhetstecken eftersom det annars skulle bli en tilldelning.
Resultatet av en jämförelse är ett heltal,
nämligen 1 (som betyder ''sant'') ifall
jämförelsen var uppfylld, annars 0 (dvs ''falskt'').
Jämförelsen a==b betraktas alltså som en beräkning vars värde
är 1 ifall a=b;
värdet är 0 om
.$ echo $(( 5>3 ))
1
$ echo $(( 2*4>=9 ))
0
$ Om man utelämnar dollartecknen ovan, så får man tester i stället för
beräkningar:$ if (( 1+1==2 )) ; then echo 'Bash kan räkna!' ; fi
Bash kan räkna!
$
Variabeln RANDOM, som är inbyggd i Bash, ger ett slumptal
mellan 0 och 32767.$ echo $RANDOM
12281
$ echo $RANDOM
31550
$ echo $RANDOM
3487
$ Om vi vill ha ett slumptal mellan tex 0 och 100,
så kan vi först låta Bash ge oss ett slumptal
mellan 0 och 32767, och sedan ta resten vid division
av detta tal med 101:$ echo $(( $RANDOM%101 ))
37
$ För att simulera ett tärningskast behöver vi
ett slumptal mellan 1 och 6. Vi beräknar då först
ett slumptal mellan 0 och 5, och adderar sedan 1 till detta:$ echo $(( $RANDOM%6+1 ))
4
$ Programmet räkna nedan
beräknar två slumptal mellan 1 och 10. Programmet
frågar efter summan, och det ger sig inte förrän
man har svarat rätt.
#!/bin/bash TAL1=$(( $RANDOM%10+1 )) TAL2=$(( $RANDOM%10+1 )) read -p "Vad är $TAL1+$TAL2? " SVAR until (( SVAR == TAL1+TAL2 )) do echo 'Fel fel fel!' read -p "Ange $TAL1+$TAL2 igen: " SVAR done echo 'Rätt svar!'
Om det svar man matar in är fel, så
skrivs texten ''Fel fel fel!'' ut, och
man får sedan göra ett nytt försök.$ räkna
Vad är 5+7? 8
Fel fel fel!
Ange 5+7 igen: 12
Rätt svar!
$ räkna
Vad är 1+1? 2
Rätt svar!
$ Vid den andra körningen fick vi ett lätt problem,
1+1, och lyckades därmed svara rätt första gången.
Därför kördes aldrig kommandona mellan
do och done.
Instruktionen declare -i namn anger att
variabeln namn är ett heltal. Fördelen med detta
är att värdet av namn då beräknas automatiskt, dvs
även om tecknen $(( och )) utelämnas.
I följande program, som visar ännu ett sätt att låta en heltalsvariabel
genomlöpa ett antal värden, har en variabel markerats som heltal:
#!/bin/bash declare -i tal=1 echo -n 'Några tal:' while (( tal<=10 )) ; do echo -n " $tal" tal=tal+1 done echo '.'
Utskriften från programmet blir
Några tal: 1 2 3 4 5 6 7 8 9 10.
Operatorn += är en kombination av addition och tilldelning. Till exempel har a+=3 värdet a+3, och som en sidoeffekt av beräkningen a+=3 får a värdet a+3. Operatorerna -=, *= osv fungerar på motsvarande sätt. Programmet ovan kan alltså skrivas så här istället:
#!/bin/bash declare -i tal=0 echo -n 'Några tal:' while (( (tal+=1)<=10 )) ; do echo -n " $tal" done echo '.'
Oftast är den förra versionen av programmet att föredra eftersom den senare versionen är mer svårläst.
Bash kan hantera så kallade fält.
Ett fält är en slags variabel som kan
innehålla många olika värden.
Värdena skiljs
åt med hjälp av olika nummer som kallas för
deras index.
Index kan vara allt från 0 och uppåt.
Kommandot fält[n]=värde
lagrar värdet värde i fältet
fält under index n.
Vi ger ett exempel:$ MANAD[3]=mars
$Nu har vi lagrat värdet mars
i fälet MANAD och gett det index 3.
För att få tillbaka värdet gör man så här:$ echo Nu är det ${MANAD[3]}
Nu är det mars
$För att referera till värdet med index n i fältet
fält skriver man alltså
${fält[n]}.
Låt oss använda ett annat index i samma fält:$ MANAD[4]=april
$Nu finns de båda värdena mars och april
lagrade under index 3 respektive 4 i fältet MANAD.$ echo Efter ${MANAD[3]} kommer ${MANAD[4]}
Efter mars kommer april
$
Man kan tilldela
flera fältvärden samtidigt på följande sätt:$ VECKODAG=(måndag tisdag onsdag torsdag fredag lördag söndag)
$Det första värdet inom parenteserna får index 0, det andra index 1 osv.$ echo Vilodagen heter ${VECKODAG[6]}
Vilodagen heter söndag
$Om man skriver * eller @ som index,
så får man alla värdena i fältet:$ echo ${VECKODAG[*]}
måndag tisdag onsdag torsdag fredag lördag söndag
$(Detta är analogt med parametrarna * och @,
som står för samtliga argument till ett Bashprogram.
Citationstecknen har motsvarande verkan i fallet med fält.)
Man kan ange index då flera fältvärden tilldelas samtidigt:$ MANAD=([1]=januari februari [5]=maj juni [12]=december)
$Värdet januari lagras under index 1.
Vi gav inget index för februari ovan,
så det lagras under det följande indexnumret,
nämligen 2. Värdena maj och juni lagras under index
5 respektive 6. Slutligen lagras december under index 12.$ echo ${MANAD[6]}
juni
$ allaargument "${MANAD[@]}"
Totalt 7 argument.
Ett argument är januari.
Ett argument är februari.
Ett argument är mars.
Ett argument är april.
Ett argument är maj.
Ett argument är juni.
Ett argument är december.
$
Här är ett enkelt program som använder fält:
#!/bin/bash
TAL=([1]=ett två tre fyra fem sex sju åtta nio tio)
echo ${TAL[$1]}
Programmet tar emot ett argument, som ska vara ett tal mellan
1 och 10. Talet skrivs sedan ut med bokstäver:$ skrivtal 3
tre
$Med hjälp av ett andra fält kan vi lära programmet
att skriva ut alla tal upp till 99:
#!/bin/bash
ENTAL=([1]=ett två tre fyra fem sex sju åtta nio tio elva \
tolv tretton fjorton femton sexton sjutton arton nitton)
TIOTAL=([2]=tjugo trettio fyrtio femtio sextio sjuttio åttio nittio)
if (( $1>19 )) ; then
echo -n ${TIOTAL[$1/10]}
set $(( $1%10 ))
fi
echo ${ENTAL[$1]}
Låt oss köra programmet en par gånger innan vi förklarar det:$ skrivtal 57
femtiosju
$ skrivtal 3
tre
$ skrivtal 14
fjorton
$För att slippa mata in alla de 99 olika värdena i programmet
har vi separerat tiotalssiffran från entalssiffran
för alla tal från och med 20.
När argumentet är 57 skrivs ordet ''femtio'' ut
av det första echo-kommandot och
ordet ''sju'' av det andra echo-kommandot.
Flaggan -n anger att inget nyrad-tecken ska skrivas ut.
Därför hamnar orden ''femtio'' och ''sju'' efter varandra
på samma rad.
Ordet ''femtio'' är värdet med index 5 i fältet
TIOTAL.
Som index anger vi $1/10,
dvs första argumentet delat med 10. Detta avrundas nedåt
till ett heltal, och ger därför talets första siffra
(förutsatt att talet inte är större än 99).
Lägg märke till att beräkningen av index sker automatiskt,
dvs man behöver inte använda $((...)).
När vi ''förbrukat'' första siffran kastar vi bort
den genom att med ett set-kommando ändra första argumentet
till det uträknade värdet av $1%10.
Procenttecknet står för ''resten vid heltalsdivision'',
och resten vid division med 10 är talets sista siffra.
På motsvarande sätt kan vi lära programmet att klara alla tal upp till 999:
#!/bin/bash
ENTAL=([1]=ett två tre fyra fem sex sju åtta nio tio elva \
tolv tretton fjorton femton sexton sjutton arton nitton)
TIOTAL=([2]=tjugo trettio fyrtio femtio sextio sjuttio åttio nittio)
(( $1>99 )) && echo -n ${ENTAL[$1/100]}hundra && set $(( $1%100 ))
(( $1>19 )) && echo -n ${TIOTAL[$1/10]} && set $(( $1%10 ))
echo ${ENTAL[$1]}
Om talet är tresiffrigt, så skrivs första siffran ut
följt av ordet ''hundra'', varefter bara de båda sista
siffrorna behålls. Sedan fungerar programmet som tidigare,
men det är något mer kompakt skrivet.$ skrivtal 88
åttioåtta
$ skrivtal 388
trehundraåttioåtta
$ skrivtal 701
sjuhundraett
$
Man kan göra delprogram, funktioner, i sina Bash-program. Här är ett exempel, en ny version av hejvärlden:
#!/bin/bash
function dekorera()
{
echo '****************************************'
echo '****************************************'
echo '** Program: hejvärlden **'
echo '** Copyright (c) 1997 Göran Andersson **'
echo '****************************************'
echo '****************************************'
}
dekorera
echo "Hej, världen!"
Först definieras funktionen dekorera.
Varje gång funktionen anropas i programmet
utförs de kommandon som står mellan klamrarna.
Ett anrop av funktionen går till precis som
ett anrop av till exempel programmet date: man skriver helt
enkelt dess namn.
Den första raden i själva programmet anropar
funktionen. Den andra och sista programraden
skriver sedan ut texten ''Hej, världen!''.$ hejvärlden
****************************************
****************************************
** Program: hejvärlden **
** Copyright (c) 1997 Göran Andersson **
****************************************
****************************************
Hej, världen!
$
Funktioner kan ta argument precis som vanliga program. De är därför mycket mer användbara än alias. I programmet filinformation nedan finns en funktion som tar fyra argument. Dessa argument är tänkta att vara utskriften från wc, så det fjärde argumentet är namnet på en fil medan de tre första är antalet rader, ord och tecken i filen.
#!/bin/bash
function information()
{
echo "Filen $4 har $1 rader och är $3 byte lång."
}
for i ; do
information $(wc "$i")
done
Programmet kör wc på
varje fil vars namn finns bland
dess argument.
Utskriften från wc blir argument till funktionen
information. I funktionen skrivs
det ut hur många rader och tecken det finns i filen.$ filinformation bellman lenngren
Filen bellman har 12 rader och är 372 byte lång.
Filen lenngren har 19 rader och är 649 byte lång.
$
En funktion i ett skalprogram fungerar ungefär som vilket fristående kommando som helst. Skillnaden är att ingen ny process dras igång, funktionen tolkas av samma Bashprocess som tolkar de övriga delarna av programmet. Därför kan man tex använda samma variabler i funktionen som i de övriga delarna av programmet; om en variabel får ett nytt värde i funktionen så påverkas dess värde i huvudprogrammet, och om den nuvarande katalogen ändras med kommandot cd i funktionen, så påverkar denna ändring hela programmet.
Följande program gör samma sak som programmet räkna i avsnitt 11.2. Den har en funktion, skriv_svar, som tar en textsträng som argument. Funktionen skriver ut textsträngen som ett meddelande, och läser sedan in variabeln SVAR.
#!/bin/bash
function las_in_svar()
{
read -p "$1" SVAR
}
TAL1=$(( $RANDOM%10+1 ))
TAL2=$(( $RANDOM%10+1 ))
las_in_svar "Vad är $TAL1+$TAL2? "
until (( SVAR == TAL1+TAL2 ))
do
echo 'Fel fel fel!'
las_in_svar "Ange $TAL1+$TAL2 igen: "
done
echo 'Rätt svar!'
Så här kan vi lära programmet skrivtal alla tal upp till en miljon:
#!/bin/bash
ENTAL=([1]=ett två tre fyra fem sex sju åtta nio tio elva \
tolv tretton fjorton femton sexton sjutton arton nitton)
TIOTAL=([2]=tjugo trettio fyrtio femtio sextio sjuttio åttio nittio)
function tilltusen()
{
(( $1>99 )) && echo -n ${ENTAL[$1/100]}hundra && set $(( $1%100 ))
(( $1>19 )) && echo -n ${TIOTAL[$1/10]} && set $(( $1%10 ))
echo -n ${ENTAL[$1]}
}
if (( $1>999 )) ; then
tilltusen $(( $1/1000 ))
echo -n tusen
fi
tilltusen $(( $1%1000 ))
echo
Den gamla versionen av skrivtal utgör
nu funktionen tilltusen.
Om talet har fler än tre siffror, så körs
tilltusen med talet delat med 1000 som argument,
och ordet ''tusen'' skrivs ut.
Därefter körs tilltusen med talets tre sista siffror
som argument.$ skrivtal 254388
tvåhundrafemtiofyratusentrehundraåttioåtta
$ skrivtal 7000
sjutusen
$
En funktion som anropar sig själv sägs vara rekursiv. Programmet träd nedan har en rekursiv funktion, kataloger. Programmet ritar ett diagram över underkatalogerna till en given katalog. Om ett argument ges till träd så används detta som startkatalog, annars startar träd i den nuvarande katalogen.
#!/bin/bash
function kataloger()
{
local FIL KAT M N INDRAG
declare -i N=0 M=1
echo -n "$1"
INDRAG="$2${1//?/ }"
cd "$1"
for FIL in * ; do
[ -d "$FIL" ] && KAT[N+=1]="$FIL"
done
if (( N==0 )) ; then
echo
elif (( N==1 )) ; then
echo -n '---'
kataloger "${KAT[1]}" "$INDRAG "
elif (( N>1 )) ; then
echo -n '-+-'
kataloger "${KAT[1]}" "$INDRAG | "
while (( (M+=1)<N )) ; do
echo -n "$INDRAG |-"
kataloger "${KAT[M]}" "$INDRAG | "
done
echo -n "$INDRAG"' `-'
kataloger "${KAT[N]}" "$INDRAG "
fi
cd ..
}
kataloger "${1:-.}" ''
Funktionen ska anropas med två argument;
det första anger startkatalogen och det andra är en
textsträng som ska skrivas ut före varje katalognamn.
Funktionen använder ett antal lokala variabler.
En lokal variabel är unik för varje enskild körning av
funktionen. Lokala variabler får alltså vara ifred inom funktionen,
de kan inte ändras någon annanstans.
Låt oss prova programmet!$ träd /usr/local
/usr/local-+-bin
|-include
|-lib-+-netscape
| |-site_perl---i386-linux
| |-texmf---doc
| `-xemacs---site-lisp
|-man
|-sbin
`-share---emacs-+-19.34---site-lisp
|-20.2---site-lisp
`-site-lisp
I detta avsnitt ska vi ge ett
programexempel som är något större än de tidigare.
Programmet vi ska skriva är ett spel
som går ut på att gissa en hemlig kod som datorn
har skapat. Koden består av fem olika bokstäver
från A till J. För varje gissning anger datorn hur
många rätt man har - dels hur många bokstäver i
gissningen som är helt rätt (rätt bokstav på rätt
position), dels hur många bokstäver som är delvis rätt
(rätt bokstav men fel position).
En spelomgång kan se ut så här:$ spel
Ange 5 symboler (bland ABCDEFGHIJ): ABCDE
0 Guld, 2 Silver
Ange 5 symboler (bland ABCDEFGHIJ): ABFGH
0 Guld, 3 Silver
Ange 5 symboler (bland ABCDEFGHIJ): ACIGH
1 Guld, 1 Silver
Ange 5 symboler (bland ABCDEFGHIJ): BDIFG
2 Guld, 3 Silver
Ange 5 symboler (bland ABCDEFGHIJ): DFIBG
2 Guld, 3 Silver
Ange 5 symboler (bland ABCDEFGHIJ): GDIBF
5 Guld, 0 Silver
Rätt svar!
Hejdå, och tack för den här gången!
$Antalet ''guld'' är antalet av de gissade bokstäverna
som är helt rätt, medan antalet ''silver'' är
antalet bokstäver som är delvis rätt.
När man ska skriva ett sådant program är det lämpligt att börja med att strukturera det. Detta innebär att man funderar ut vad som behöver göras och delar upp problemet i mindre delproblem som kan lösas separat. Ifall problemet/programmet är mycket stort, så brukar man först dela upp det i stora delproblem; dessa delproblem delas sedan upp i mindre delproblem och så vidare.
Så vad ska vårt spelprogram göra? Jo, först måste det skapa den hemliga koden. Därefter ska användaren få skriva in sin gissning, och programmet ska beräkna och skriva ut antalet poäng. Om gissningen inte var exakt rätt, så ska användaren få göra en ny gissning. De svåraste uppgifterna är förmodligen följande:
Man kan modifiera spelreglerna och tillåta en kod där bokstäverna inte är olika. Koden behöver inte heller bestå av exakt fem bokstäver, fyra eller sex bokstäver kunde gå lika bra. Och varför ska det vara just tio olika bokstäver att välja mellan? Dessutom skulle man kunna använda andra symboler än bokstäver i koden, till exempel siffror. Vi vill skriva programmet så att det blir lätt att ändra spelreglerna. För att uppnå detta inför vi ett antal variabler vars värden anger spelreglerna. Variabeln KODLANGD ska ange kodens längd, som i vår exempelkörning är 5. Variabeln SYMBOLER ska ange vilka symobler man får välja bland. Variabeln OLIKA_SYMBOLER ska vara ''Ja'' om koden måste bestå av olika symboler, annars ''Nej''. Ett standardtrick är att först definiera JA som 1 och NEJ som 0, och sedan definiera OLIKA_SYMBOLER som antingen JA eller NEJ.
Den hemliga koden lagras i en global variabel med namnet HEMLIG_KOD och vars värde ska vara en textsträng bestående av KODLANGD stycken symboler bland dem som anges av variabeln SYMBOLER. Varje gissning lagras på motsvarande sätt i variabeln GISSNING. Så här ser programmet ut:
#!/bin/bash
declare -i JA=1
declare -i NEJ=0
# Längden av den hemliga koden (antal positioner):
declare -i KODLANGD=5
# Ska symbolerna i den hemliga koden vara olika?
OLIKA_SYMBOLER=$JA
# Vilka symboler som ska användas (OBS!
# Dessa måste vara olika):
SYMBOLER=ABCDEFGHIJ
# Antal symboler att välja bland:
declare -i ANTAL_SYMBOLER=${#SYMBOLER}
# HEMLIG_KOD ska innehålla den hemliga koden,
# GISSNING ska innehålla den senaste gissningen
# Följade ska ange antalet poäng för den senaste gissningen:
declare -i POANG_GULD=0
declare -i POANG_SILVER=0
function skapa_hemlig_kod()
{
local N SYMB=$SYMBOLER SLUMPTAL NY
HEMLIG_KOD=''
declare -i N=0
while (( (N+=1)<=KODLANGD )) ; do
# Välj ny symbol slumpmässigt
SLUMPTAL=$RANDOM%${#SYMB}
NY=${SYMB: $SLUMPTAL: 1}
HEMLIG_KOD=$HEMLIG_KOD$NY
# Om symbolerna i den hemliga koden ska vara olika,
# så ta bort den valda symbolen från SYMB:
(( OLIKA_SYMBOLER )) && SYMB=${SYMB/$NY/}
done
}
function las_in_gissning()
{
read -p "Ange $KODLANGD symboler (bland $SYMBOLER): " GISSNING
# Stryk alla icke tillåtna tecken från GISSNING:
GISSNING=${GISSNING//[^$SYMBOLER]/}
# Finns det rätt antal tecken kvar i GISSNING?
if (( ${#GISSNING} != $KODLANGD )) ; then
echo 'Felaktig gissning, försök igen!'
las_in_gissning
fi
}
function berakna_poang()
{
local N KOD=$HEMLIG_KOD S
declare -i N=0
# Beräkna först antalet guld.
POANG_GULD=0
# Jämför symbol för symbol mellan
# GISSNING och KOD
while (( N<${#KOD} )) ; do
S=${KOD: $N: 1}
if [ ${GISSNING: $N: 1} == $S ] ; then
POANG_GULD=POANG_GULD+1
# Plocka bort den symbol som gav poäng
# så att den inte senare ger silver också:
GISSNING=${GISSNING/$S/}
KOD=${KOD/$S/}
else
N=N+1
fi
done
# Beräkna nu antalet silver.
# För varje symbol i koden, stryk den första eventuella
# förekomsten av den från GISSNING.
while (( (N-=1)>=0 )) ; do
GISSNING=${GISSNING/${KOD: $N: 1}/}
done
# Antal silver = antalet strukna symboler i GISSNING:
POANG_SILVER=${#KOD}-${#GISSNING}
echo " $POANG_GULD Guld, $POANG_SILVER Silver"
}
skapa_hemlig_kod
while (( POANG_GULD != KODLANGD )) ; do
las_in_gissning
berakna_poang
done
echo 'Rätt svar!'
echo 'Hejdå, och tack för den här gången!'
Om ett kommando misslyckas, så fortsätter Bash som vanligt utan att bry sig om felet. Betrakta till exempel följande program:
#!/bin/bash cp bellmna bellmna.kopia cp bellman bellman.kopia
Så här går det när vi kör programmet:$ ls bell*
bellman
$ fel
cp: bellmna: Filen eller katalogen finns inte
$ ls bell*
bellman bellman.kopia
$Det andra kommandot i programmet kördes
trots att det första kommandot misslyckades och gav
ett felmeddelande.
Ibland vill man att programkörningen ska avbrytas
omedelbart när ett fel uppstått.
I så fall ska man ha med kommandot set -e
i programmet. Vi ändrar det till följande:
#!/bin/bash set -e cp bellmna bellmna.kopia cp bellman bellman.kopia2
Och så provar vi igen:$ fel
cp: bellmna: Filen eller katalogen finns inte
$ ls bell*
bellman bellman.kopia
$Den här gången avbröts programmet efter
kommandot som misslyckades.
Om man vill att fel återigen ska ignoreras,
så ska man ge kommandot set +e.
I detta kapitel introduceras programmet make som kan hjälpa en att få något gjort.
Antag att vi arbetar med ett LATEX-dokument som är uppdelat på flera filer: huvudfilen gnulinux.tex samt definitioner.tex och unix.tex. Innan dokumentet kan tryckas är det flera saker som måste göras. Först ska det typsättas av LATEXmed kommandot latex gnulinux.tex. Då skapas filen gnulinux.dvi. Denna fil översätts sedan till postscript så att skrivaren kan ta emot den. Kommandot dvips -o gnulinux.ps gnulinux.dvi. skapar postscriptfilen gnulinux.ps, som skrivs ut med kommandot lpr gnulinux.ps.
Alla dessa steg är tröttsamma att gå igenom, och det är lätt hänt att man gör fel i något av stegen. Varje gång man gör en ändring i någon av sina LATEX-filer måste dessutom alla eller vissa av stegen göras om. Slutsatsen blir att det borde finnas ett program, tex med namnet make, som gör arbetet åt en. Slutsatsen är korrekt: det finns ett sådant program.
För att få hjälp av make med en viss syssla ska man i en fil med namnet Makefile beskriva sysslan. När denna fil väl är skapad, så räcker det att skriva make mål varje gång man vill få sysslan mål utförd. Denna syssla kan, som i exemplet ovan, vara att typsätta och trycka ett dokument. Det kan också vara att kompilera ett program. Man kan inte få hjälp med att koka kaffe, men faktum är att många vitt skilda sysslor som kan utföras av ett antal Bash-kommandon kan automatiseras med hjälp av make. Frågan är nu hur en Makefile ser ut. Resten av detta kapitel ägnas åt att besvara den frågan.
En Makefile som tar hand om typsättningen som beskrivs ovan kan se ut så här:
gnulinux.dvi: gnulinux.tex definitioner.tex unix.tex
latex gnulinux.tex
gnulinux.ps: gnulinux.dvi
dvips -o gnulinux.ps gnulinux.dvi
utskrift: gnulinux.ps
lpr gnulinux.ps
Filen ovan innehåller tre regler.
Den första regeln säger att filen gnulinux.dvi skapas
från filerna gnulinux.tex, definitioner.tex
och unix.tex med kommandot latex gnulinux.tex.
Den andra regeln talar om hur gnulinux.ps
skapas från gnulinux.dvi. Den sista regeln
anger hur filen gnulinux.ps skrivs ut.
Låt oss prova!$ ls
Makefile definitioner.tex gnulinux.tex unix.tex
latex gnulinux.tex
This is TeX, Version 3.14159 (C version 6.1)
(gnulinux.tex
LaTeX2e <1996/12/01>
Babel <v3.6h> and hyphenation patterns for american, swedish, loaded.
(/usr/lib/texmf/tex/latex/base/book.cls
Document Class: book 1996/10/31 v1.3u Standard LaTeX document class
(/usr/lib/texmf/tex/latex/base/bk12.clo)) (definitioner.tex)
No file gnulinux.aux.
[1] [2] (gnulinux.aux) )
(see the transcript file for additional information)
Output written on gnulinux.dvi (2 pages, 1040 bytes).
Transcript written on gnulinux.log.
dvips -o gnulinux.ps gnulinux.dvi
This is dvipsk 5.58f Copyright 1986, 1994 Radical Eye Software
' TeX output 1997.11.17:1447' -> gnulinux.ps
<tex.pro>. [1] [2]
lpr gnulinux.ps
Låt oss göra en ny utskrift:$ ls
Makefile gnulinux.aux gnulinux.log gnulinux.tex
definitioner.tex gnulinux.dvi gnulinux.ps unix.tex
$ make utskrift
lpr gnulinux.ps
$Som synes struntade make denna gång i att köra
latex och dvips, filen gnulinux.ps
skrevs ut direkt. På något magiskt sätt
(som vi snart ska förklara) visste make att
filen gnulinux.ps var ''up to date'' och
att det var onödigt att köra latex igen.
Hmm, antag att vi ändrat lite i tex unix.tex
och sedan provar igen:$ ls -t
unix.tex gnulinux.aux gnulinux.tex
gnulinux.ps gnulinux.dvi unix.tex~
gnulinux.log Makefile definitioner.tex
$ make utskrift
latex gnulinux.tex
This is TeX, Version 3.14159 (C version 6.1)
(gnulinux.tex
LaTeX2e <1996/12/01>
Babel <v3.6h> and hyphenation patterns for american, swedish, loaded.
(/usr/lib/texmf/tex/latex/base/book.cls
Document Class: book 1996/10/31 v1.3u Standard LaTeX document class
(/usr/lib/texmf/tex/latex/base/bk12.clo)) (definitioner.tex) (gnulinux.aux)
[1] (unix.tex) [2] (gnulinux.aux) )
(see the transcript file for additional information)
Output written on gnulinux.dvi (2 pages, 2328 bytes).
Transcript written on gnulinux.log.
dvips -o gnulinux.ps gnulinux.dvi
This is dvipsk 5.58f Copyright 1986, 1994 Radical Eye Software
' TeX output 1997.11.17:1524' -> gnulinux.ps
<tex.pro>. [1] [2]
lpr gnulinux.ps
$Nu körde make återigen latex och dvips
före lpr.
Reglerna i en Makefile är av formen
mål: delmål1 delmål2 ...Regeln inleds med namnet på ett mål för make. Vanligtvis är namnet på målet identiskt med namnet på en fil som regeln är till för att skapa. Vår första regel i exemplet ovan har som mål gnulinux.dvi, och regeln är till för att skapa filen gnulinux.dvi.
kommando
kommando
...
Efter namnet på målet ska man skriva ett kolon, och därefter på samma rad alla eventuella delmål, dvs mål som måste uppnås innan det angivna målet kan uppnås. För att klara av ett delmål letar make först efter en regel som talar om hur det uppnås, och om det finns ett sådant så tar make hand om det först. Om det inte finns en regel för delmålet, så försöker make finna en fil med samma namn som delmålet; finns det inte heller någon sådan fil, så klagar make över att ''det finns ingen regel för att göra målet xxx, som behövs för målet yyy'' och körningen avbryts.
Efter raden som anger målet kan man ha ett eller flera kommandon som ska utföras för att målet ska uppnås. Före varje kommando måste det finnas ett tabulatorsteg. (Det går inte att skriva några mellanslag i stället. I början gör man ofta fel på detta.)
Kommandona utförs inte automatiskt, utan bara om make anser att målet inte är ''up to date''. Det kan finnas olika skäl till att målet måste uppdateras:
När vi i avsnitt 13.1 första gången gav kommandot make utskrift, så betraktade make först delmålet gnulinux.ps. Det fanns en regel för gnulinux.ps, som make gick till. Där betraktades delmålet gnulinux.dvi, så make hoppade till regeln gnulinux.dvi. Delmålen där, de tre LATEX-filerna, fanns det ingen regel för, men däremot fanns de som filer i den aktuella katalogen. Alltså var delmålen till gnulinux.dvi klara, men eftersom det inte fanns någon fil med namnet gnulinux.dvi körde make kommandot i regeln gnulinux.dvi. Därmed var filen gnulinux.dvi skapad och motsvarande mål uppnått. Sedan återvände make till gnulinux.ps och körde kommandot i den regeln eftersom dess delmål hade uppdaterats (men också för att det filen gnulinux.ps inte fanns). Nu var också målet gnulinux.ps klart, och make återvände till målet utskrift vars kommandon kördes eftersom det inte fanns någon fil med det namnet (och för att delmålet hade uppdaterats).
Den andra gången vi gav kommandot make utskrift gick make till delmålen gnulinux.ps och gnulinux.dvi. Målet gnulinux.dvi behövde inte uppdateras eftersom det fanns en fil med detta namn som också var nyare än alla dess delmål. Inte heller gnulinux.ps behövde uppdateras eftersom den var nyare än gnulinux.dvi. Däremot kördes kommandona i målet utskrift eftersom det inte fanns någon fil med namnet utskrift.
Den tredje gången vi körde make utskrift gick make återigen till delmålen gnulinux.ps och gnulinux.dvi. Den här gången var ett av delmålen till gnulinux.dvi nyare än filen gnulinux.dvi, så make körde kommandot i målet gnulinux.dvi. Därmed måste även gnulinux.ps uppdateras före utskriften.
Här är ett nytt exempel:$ make gnulinux.ps
make: `gnulinux.ps' is up to date.
$ touch gnulinux.dvi
$ make gnulinux.ps
dvips -o gnulinux.ps gnulinux.dvi
This is dvipsk 5.58f Copyright 1986, 1994 Radical Eye Software
' TeX output 1997.11.17:1524' -> gnulinux.ps
<tex.pro>. [1] [2]
$ Första gången vi ger kommandot make gnulinux.ps ovan
är filen gnulinux.ps nyare än gnulinux.dvi,
så make uppdaterar den inte. Men om vi med
kommandot touch petar på gnulinux.dvi
så att det ser ut som om den ändrats, så blir den
nyare än gnulinux.ps och då tror make
att gnulinux.ps behöver uppdateras.
Om vi hade haft otur och det funnits en fil med namnet utskrift som var nyare än filen gnulinux.ps, så skulle vi inte få vår utskrift. Detta är kanske inte vad man önskar. Men det finns ett sätt att gardera sig mot sådan otur. Om man har med en regel med namnet .PHONY och med utskrift som delmål, så struntar make i om det finns någom fil med namnet utskrift eller inte. Därigenom försäkrar man sig om att kommandona i målet alltid utförs.
Ofta tar man i sin Makefile med ett mål som gör att make kan städa upp efter sig. Detta mål brukar heta clean och har till syfte att radera alla eller en del av de filer som tillverkas automatiskt i de andra målen. I vårt exempel kan man låta clean radera gnulinux.log, gnulinux.aux och alla kopior som Emacs har gjort (de filer vars namn slutar med ett tilde), samt eventuellt också gnulinux.dvi och gnulinux.ps. Målet clean bör naturligtvis också sättas under .PHONY.
Om man ger kommandot make utan att specificera något mål, så tar make hand om det första målet i Makefile. Därför kan man sätta det mål man vanligtvis vill uppnå först. Fast det finns ett annat standardsätt att göra detta på: man brukar ha ett mål med namnet all överst i Makefile, och som delmål till all anges det eller de mål man oftast vill få utförda.
Vi ändrar alltså vår Makefile till
all: gnulinux.ps
.PHONY: all utskrift clean
gnulinux.dvi: gnulinux.tex definitioner.tex unix.tex
latex gnulinux.tex
gnulinux.ps: gnulinux.dvi
dvips -o gnulinux.ps gnulinux.dvi
utskrift: gnulinux.ps
lpr gnulinux.ps
clean:
rm *~ gnulinux.{dvi,ps,aux,log}
Och så provar vi hur det fungerar!$ ls
rm *~ gnulinux.{dvi,ps,aux,log}
latex gnulinux.tex
This is TeX, Version 3.14159 (C version 6.1)
(gnulinux.tex
LaTeX2e <1996/12/01>
Babel <v3.6h> and hyphenation patterns for american, swedish, loaded.
(/usr/lib/texmf/tex/latex/base/book.cls
Document Class: book 1996/10/31 v1.3u Standard LaTeX document class
(/usr/lib/texmf/tex/latex/base/bk12.clo)) (definitioner.tex)
No file gnulinux.aux.
[1] (unix.tex) [2] (gnulinux.aux) )
(see the transcript file for additional information)
Output written on gnulinux.dvi (2 pages, 2328 bytes).
Transcript written on gnulinux.log.
dvips -o gnulinux.ps gnulinux.dvi
This is dvipsk 5.58f Copyright 1986, 1994 Radical Eye Software
' TeX output 1997.11.18:0050' -> gnulinux.ps
<tex.pro>. [1] [2]
make: Nothing to be done for `all'.
Om något kommando i en Makefile
misslyckas, så stoppar make där.
Detta är tvärt emot tex Bash,
som vanligtvis struntar i alla fel och
bara fortsätter.
Om vi kör make clean igen,
så går det så här:$ make clean
rm *~ gnulinux.{dvi,ps,aux,log}
rm: *~: Filen eller katalogen finns inte
make: *** [clean] Error 1
$ Kommandot rm rapporterar misslyckande eftersom
en av filerna som skulle raderas inte fanns.
Därmed stannar också make med ett
felmeddelande.
I det här läget vill vi att make ska
strunta i felet. Det finns ett sätt att tala om detta:
före kommandot, direkt efter tabulatorsteget,
ska man sätta ett streck. Raden blir alltså:
-rm *~ gnulinux.{dvi,ps,aux,log}
Om vi kör make med den ändringen, så går det så
här istället:$ make clean
rm *~ gnulinux.dvi gnulinux.ps gnulinux.aux gnulinux.log
rm: *~: Filen eller katalogen finns inte
make: [clean] Error 1 (ignored)