Innehållsförteckning
- Förord
- Introduktion till Ubuntu
- Hitta hjälp i Ubuntu
-
Användare och grupper
- Skapa användare
- Ta bort användare
- Filen /etc/passwd
- Byta användarnamn
- Byta primär grupp för en användare
- Uppdatera kommentarsfältet för en användare
- Byta hemkatalog för en användare
- Byta kommmandotolk för en användare
- Filen /etc/shadow
- Hantera lösenord och konton
- Kontrollera att användardatabasen är korrekt
- Att bli en annan användare
- Grupper
- Filrättigheter
- Processhantering
- Arbeta med text
-
Kommandotolken Bash
- Kommandoprompten
- Reserverade ord
- Alias i Bash
- Historik i Bash
- Flera kommandon på samma rad
- Omdirigering och rör
- Jokertecken
- Skriva skript i Bash
- Variabler
- In- och utmatning
- Räkna med bash - de fyra räknesätten
- Villkor
- Loopar
- Argument
- Slumpade tal
- Köra program och fånga upp dem från skriptet
- Funktioner
- Returvärden
- Source
- Logghantering och felsökning
- Systemd
- Nätverk
- Diskar och filsystem
- Övning - skapa en logisk volym
Förord
Den här boken är skriven för den svenska Yrkeshögskolan under åren 2006-2024. Den passar lika bra för gymnasieskolan. Kursen jag använt boken till har ofta kallats “Linux” eller “Linux grundkurs” och det är precis vad det är. Under fem till åtta veckor har jag haft eleverna och lärt dem Linux utifrån denna bok. Texten är skriven för att någon som inte varit i kontakt med Linux skall kunna lära sig. Ofta har eleverna varit datorvana och ibland har de haft kunskap om serveradministration i Microsoft Windows. Många elever har haft det kämpigt i början av kurserna eftersom de är ovana med att skriva kommandon på en kommandorad, men efter någon vecka har de börjat vänja sig och många har till och med tyckt att det är ett bättre sätt att använda en dator än mus och ikoner.
Till min stora glädje har ett flertal elever i varje kurs upptäckt det fina med Linux och öppen- och fri programvara. Många har installerat Linux hemma på en gammal PC och fortsatt lära sig. För en del var min kurs en ögonöppnare, vilket gjorde att de bytte inriktning från Windows till Linux. Flera av mina gamla elever jobbar med Linux idag, faktum är att jag själv, efter ett par år, anställt ett par av dem på arbetsplatser jag varit på.
Jag vet att allt i boken inte är perfekt. Det finns andra sätt att göra sakerna på. Jag har försökt att hålla mig till standarder rakt genom hela boken. Att jag valde Ubuntu att använda för kurserna är för att Ubuntu är mycket enkelt att installera och lyckas med. Mitt mål har hela tiden varit att väcka ett intresse för Linux hos eleverna och göra det så enkelt jag kan för att de inte skall tycka Linux är krångligt och omständigt. Jag presenterar därför inga avancerade “smarta” lösningar i den här boken. Däremot kommer en nybörjare ha ett självförtroende att logga in på en linuxserver, felsöka och utföra enklare administration.
Jobbar du inom skola och vill använda boken i din undervisning erbjuder jag klasslicenser. Då ingår också fler övningar som är kopplade till de olika kapitlen i boken. Kontakta mig för mer information. |
Bokens omslag är ett fotografi över området där jag bor. Vattnet på bilden är Öresund och det mörka strecket i horisonten är Danmark. |
Har du frågor, tankar, idéer på bokens innehåll eller bara vill höra av dig? Du kontaktar mig enklast via epost jonas.bjork@gmail.com .
Detta verk är skyddat av upphovsrättslagen (Lag 1960:729)! Mångfaldigande, överlåtelse, försäljning, överföring eller annan form av utnyttjande av materialet får inte ske utan tillstånd från upphovsrättsinnehavaren. Den som bryter mot lagen om upphovsrätt kan åtalas av allmän åklagare och dömas till böter eller fängelse i upp till två år samt bli skyldig att erlägga ersättning till upphovsman/rättsinnehavare. |
Introduktion till Ubuntu
Vad är Linux?
Allting började med ett meddelande till nyhetsgruppen comp.os.minix på USENET den 25 augusti 1991. Linus Torvalds som då var 21 år gammal och studerade på Helsingfors tekniska universitet skrev så här:
Hello everybody out there using minix -
I’m doing a (free) operating system (just a hobby, won’t be big and professional like gnu) for 386(486) AT clones. This has been brewing since april, and is starting to get ready. I’d like any feedback on things people like/dislike in minix, as my OS resembles it somewhat (same physical layout of the file-system (due to practical reasons) among other things).
I’ve currently ported bash(1.08) and gcc(1.40), and things seem to work. This implies that I’ll get something practical within a few months, and I’d like to know what features most people would want.
Any suggestions are welcome, but I won’t promise I’ll implement them :-)
Linus (torvalds@kruuna.helsinki.fi)
PS. Yes - it’s free of any minix code, and it has a multi-threaded fs. It is NOT portable (uses 386 task switching etc), and it probably never will support anything other than AT-harddisks, as that’s all I have :-(.
Från början var Linux licensierad under egen licens, men i december 1992 publicerades version 0.99 av Linux under GNU-projektets General Public License (GPL). 1994 släpptes version 1.0 av Linux, då Linus tyckte att Linux var färdigt för en första utgåva.
När detta skrivs (hösten 2024) är Linux uppe i version 6.10.6 och är översatt till ett flertal processorarkitekturer. Linux finns överallt: i tvättmaskiner, i digital signage (digitala reklamskyltar), i robotar, i bilar, i mobiltelefoner (Android bygger på Linux), i flygplan, servrar, skrivbord, surfplattor, .. Ja, i princip överallt där man behöver ett operativsystem för att köra programkod.
Linux är en operativsystemskärna, det vill säga den programkod som låter program att kommunicera med hårdvaran. Linux i sig är inte ett komplett system, vi behöver program som kan användas ovanpå Linux. De flesta av de grundläggande programmen kommer ifrån GNU-projektet. GNU (GNU is Not Unix) skapades av Richard Stallman år 1983. Stallman ville bygga ett helt fritt operativsystem (inte fritt som i gratis, utan fritt som i frihet). Operativsystemskärnan i GNU heter HURD och skulle kunna ha blivit vad Linux är idag, men lyckades aldrig få tillräckligt många utvecklare för att få upp farten på utvecklingen. HURD är än idag ganska enkel och saknar en hel del hårdvarustöd, den senaste versionen av Hurd är version 0.9 från december 2016. Stallman skapade också den licens, GNU General Public License, som används av Linux och tusentals andra mjukvaruprojekt runt om i världen. GPL licensen ger användaren fyra friheter:
- Frihet 0
-
Friheten att använda programvaran i valfritt syfte.
- Frihet 1
-
Friheten att undersöka programmet för att förstå hur det fungerar och använda dessa kunskaper i egna syften.
- Frihet 2
-
Friheten att fritt få dela med sig av kopior för att hjälpa andra.
- Frihet 3
-
Friheten att förbättra programmet, anpassa det till egna krav och dela med sig av förbättringarna så att andra kan dra nytta av ändringarna.
Under 1990-talet var det här riktigt stort. Det är fortfarande stort, men då var det större. De flesta mjukvaruföretag använde sig av en licensmodell som gick ut på att du betalar en summa pengar och får rätten att använda programvaran. Saknar du en funktion i programvaran får du snällt be utvecklaren att lägga till den funktionen, och hoppas på att funktionen kommer in i nästa version.
Med programvara som är öppen och fri (open source) har du tillgång till källkoden själv och kan bygga vidare på den, lägga in dina funktioner som du saknar och sprida dina förändringar till andra. Utan att bryta mot något avtal. Avtalet med utvecklaren är att du äger rätten att göra detta. Så, har fri programvara ingen upphovsrätt? Nej, upphovsrätten finns alltid där. Skriver du en programvara och släpper den med en fri licens (till exempel GPL) äger du fortfarande upphovsrätten till programvaran. Den kan du inte avsäga dig från, men du ger andra rätten att använda ditt program, ändra ditt program och kopiera det till sina vänner.
Microsoft och andra stora mjukvaruföretag gillade inte alls licensmodellen. Många användare fick också för sig att mjukvara som är öppen och fri är osäkrare och man får vad man betalar för. Verkligheten hann i fatt dem och idag jobbar så gott som alla större företag med öppen programvara, till och med Microsoft släpper programvara med öppen källkod idag. Öppen och fri programvara är här för att stanna.
Har du en mobiltelefon eller surfplatta med Android som operativsystem? Den kör linuxkärnan och Android i sig är öppen källkod. Källkoden till Android finns på source.android.com.
Har du en iPhone, iPad eller Mac? Apple använde BSD-projektet för att skapa OSX och senare iOS. Kärnan för de operativsystemen heter Darwin och fanns tidigare att ladda ner från developer.apple.com.
Smart-TV från Philips, LG, Samsung, …? I princip alla av dem använder Linux för smart-tv-funktionerna.
Bredbandsroutrar från D-Link, Netgear, ASUS, Unifi med flera. Linux driver dem också. När tillverkarna slutar uppgradera systemet i routern kan vi ofta ladda ner OpenWrt och uppgradera vår router för att få senare versioner och säkerhetsuppdateringar.
För att kunna köra Linux behöver vi linuxkärnan och programvara som körs på kärnan. Detta kan vi lösa själva genom att kompilera allt från källkod. När vi kompilerar källkod tar vi textfiler som innehåll programkoden skriven i något programmeringsspråk och gör om den till binärkod (ettor och nollor) som datorn kan tolka och förstå. Att kompilera ett operativsystem är en tidskrävande process och därför skapades något som kallas linuxdistributioner. En linuxdistribution paketerar den färdigkompilerade linuxkärnan med kompilerad programvara och erbjuder ett enkelt installationsgränssnitt för att installera Linux på datorn.
Det finns hundratals olika distributioner och det kan vara svårt att veta vilken vi skall använda. Till att börja med finns det två som är mer kommersiella än andra: Red Hat Enterprise Linux (RHEL) och SUSE Enterprise Linux (SLE). Dessa två erbjuder support och kostar runt 5000 kronor per år och server att köra. De är välanvända hos större företag som vill ha stabilitet och support tillgänglig. Även om Linux och programvaran är öppen och fri så får vi alltså ta betalt för den. Det Red Hat och SUSE tar betalt för är arbetet med att uppdatera och paketera Linux, ja och supporten så klart.
Den andra grenen av linuxdistributioner är de som kallas community. Distributioner som går här under drivs av communityn (vi som använder dem). En del av dem erbjuder support mot betalning, men många hänvisar till forum på internet för support. Den absolut vanligaste linuxdistributionen i Sverige är Ubuntu. Ubuntu bygger i sin tur på distributionen Debian GNU/Linux, en av få som använder GNU i sitt namn. Från Ubuntu har det också skapats andra linuxdistributioner som Linux Mint, Kubuntu, Lubuntu med flera. Alla är inriktade på något som skiljer sig från ursprunget. Linux Mint är till exempel skapad för att vara så enkel som möjligt att komma igång med. Red Hat har en communitydistribution som heter CentOS och SUSE har openSUSE. En del användare gillar känslan av att ha kontroll över sitt system och väljer distributioner som till exempel Gentoo Linux eller Arch Linux, där de kan detaljstyra hur systemet skall byggas.
Skall vi använda Linux som skrivbordssystem, det vill säga Desktop, behöver vi en fönstermiljö. I Linux finns det ett flertal sådana också, de vanligaste och största är KDE och GNOME. Det är skrivbordsmiljöerna som gör att vi får en grafisk miljö med fönster och ikoner, utan den använder vi Linux i textläge - normalt en svart bakgrund med grå text.
Det har gjorts en dokumentär om Linux som heter The Code, den finns att se på till exempel YouTube - sök efter the code linux documentary. |
Installera Ubuntu
Den första versionen av Ubuntu släpptes den 20 oktober 2004 och hette Warty Warthog. Version 4.10 var början på något helt nytt. Mark Shuttleworth från Sydafrika hade gjort sig en förmögenhet på att sälja Thawte som på den tiden var en av de största certifikatsutgivarna, de certifikat som används i till exempel webbläsare för att kryptera kommunikationen mellan din webbläsare och webbservern. Mark skrev den första buggrapporten den 20:e augusti 2004: Microsoft has a majority market share och ville skapa ett fritt operativsystem som alla kan använda. Det är Marks företag Canonical som ligger bakom Ubuntu. År 2013 stängde Mark buggen, med hänvisning till att Linux kommit långt sedan 2004, launchpad.net.
Ubuntu kommer i en ny version var sjätte månad, ofta i april och oktober. Varje version har ett projektnamn som kommer från ett djur och varje version numreras med aktuellt år och månad. Versionen som släpptes i april 2024 blev version 24.04 (24 efter årtalet 2024 och 04 efter månad 04 - april). Varannat år blir aprilversionen också en Long Term Support version (LTS). Det innebär att versionen kommer få uppdateringar under en längre tid - åtta år. De versioner som inte är LTS får uppdateringar under nio månader.
Version | Namn | Release | End of Life |
---|---|---|---|
24.04 | Noble Numbat | april 2024 | juni 2029 |
22.04 | Jammy Jellyfish | april 2022 | juni 2027 |
20.04 | Focal Fossa | april 2020 | april 2025 |
För system som skall användas i produktion är det lämpligt att använda Long Term Support (LTS) versionerna av Ubuntu, eftersom de kommer få uppdateringar under en längre tid. Den senaste Long Term Support (LTS) versionen av Ubuntu är 24.04 (Noble Numbat). Den version som inte är LTS innehåller ofta de senaste versionerna av olika programvaror och lämpar sig till att till exempel använda för vår arbetsdator.
Ubuntu kommer i flera olika utgåvor: Ubuntu Desktop, Ubuntu Server, Ubuntu for IoT och Ubuntu Cloud. De har samma grund och skillnaden är vad som installeras med dem. Vi kan till exempel installera Ubuntu Server och sedan installera de paket som behövs för att få igång Ubuntu Desktop på systemet. I den här boken kommer vi kommer använda Ubuntu Server som bas.
Systemkrav för att köra Ubuntu Server
För att kunna köra Ubuntu Server behöver vi ha en 64-bitars processor med lägsta klockfrekvensen 1GHz: Intel/AMD (amd64), ARM (arm64), POWER8/POWER9 (ppc64el) eller IBM Z/LinuxONE (s390x). Det vanligaste är att vi har en processor från Intel eller AMD i vår dator/server. Denna processorarkitektur kallas amd64. Vi behöver också ha 1GiB RAM-minne och 5 GiB disklagring.
- 64-bitars processor med minst 1GHz från Intel/AMD, ARM, POWER8/POWER9 eller IBM Z/LinuxONE.
- Minst 1GiB RAM-minne, gärna 3 GiB eller mer
- Minst 5 GiB disklagring, gärna 25 GiB eller mer
Som vanligt gäller att mer RAM-minne och kraftfullare processor ger bättre prestanda. Likaså ger snabbare hårddiskar som SSD och NVMe bättre prestanda.
Ladda ner Ubuntu Server
Vi laddar ner installationen av Ubuntu Server från https://ubuntu.com/download/server .
När vi skall ladda ner installationen ser vi till att det är version 24.04 och vi väljer fliken Manual Installation. Vi klickar på den gröna knappen Download 24.04 LTS för att påbörja nedladdningen.
Nedladdningen startar automatiskt i vår webbläsare och vi får möjligheten att prenumerera på Ubuntus nyhetsbrev och ladda ned ett dokument med vanliga kommandon (Ubuntu CLI cheatsheet).
Installera Ubuntu Server
Om vi har möjlighet att ge vår server mer resurser är det bra, ju mer resurser - desto bättre prestanda kommer vi få ut. För att det inte skall bli allt för långsamt när vi jobbar med servern bör vi ha minst:
- 4 GiB RAM (4096 MiB)
- 2 CPU (cores)
- 30 GiB DISK
Installationen steg för steg:
Ubuntu Server, tryck ENTER
Välj språk: ‘English’
Keyboard configuration. Layout: ‘Swedish’ och Variant: ‘Swedish’ . Hoppa ner till ‘Done’ och tryck ‘ENTER’.
Network connections. Här trycker vi ‘Done’ och går vidare.
Configure proxy Om vi har en proxy för att nå internet i vårt nätverk behöver vi ange den här. Om vi har en sådan vet vi om det. Oftast är det bara att välja ‘Done’ och gå vidare här.
Configure Ubuntu archive mirror Här anger vi vilken adress det är till paketförrådet vi vill använda. Ubuntu hittar oftast rätt själv,
http://se.archive.ubuntu.com/ubuntu
. Tryck ‘Done’ för att gå vidare.Guided storage configuration Här väljer vi ‘Use an entire disk’ och ‘Set up this disk as an LVM group’. Vi väljer ‘Done’ för att komma vidare.
Storage configuration Här får vi se en sammanfattning på hur vår disk kommer konfigureras. Vi väljer ‘Done’ för att komma vidare.
Confirm destructive action Här kommer en dialogruta upp som frågar om vi är riktigt säkra på att vi vill göra detta med vår disk. Om vi skapar en virtuell maskin kommer inget raderas från vår dator, men om vi installerar Ubuntu direkt på en dator - utan virtualisering kan detta vara farligt. Om vi installerar Ubuntu direkt på vår dator (alltså inte i en virtuell maskin) måste vi se till att vi har gjort en säkerhetskopia på hårddisken innan vi går vidare! I sämsta fall kommer allt på disken att raderas. Är vi säkra på att gå vidare väljer vi ‘Continue’, annars väljer vi ‘No’.
-
Profile setup Här skall vi skapa ett användarkonto och välja ett namn på vårt ubuntusystem:
Notera att vi bör undvika å,ä och ö här. Inte heller mellanslag och andra specialtecken är bra att använda - förutom i lösenordet så klart.
- Your name Här skriver vi in vårt namn, till exempel: ‘jonas bjork’
- Your server’s name Här väljer vi ett namn för vårt system, till exempel: ‘ubuntuserver’
- Pick a username Här väljer vi ett användarnamn, till exempel: ‘jonas’ . Det är det här namnet som vi kommer logga in på Ubuntu med.
Choose a password Här väljer vi ett lösenord. Vi ser till att det inte är alldeles för enkelt.
Confirm your password Här skriver vi samma lösenord igen. Sedan väljer vi ‘Done’ för att komma vidare.
SSH Setup SSH är en tjänst som gör att vi kan ansluta till vår ubuntuserver över nätverk. Denna vill vi installera, så vi markerar ‘Install OpenSSH server’ genom att trycka på ‘Mellanslag’ när vi står i rutan. Sedan går vi ner till ‘Done’ för att gå vidare med installationen.
Featured Server Snaps Här väljer vi ingenting, utan bara hoppar ner till ‘Done’ för att komma vidare.
Install complete! Nu installeras Ubuntu på vår dator. Vi väntar ett tag. När installationen är klar kan vi välja ‘Reboot’ för att starta om datorn.
Vi avmonterar cd-skivan vi installerat från och trycker ‘Enter’. Om vi använt ett USB-minne för att installera Ubuntu Server drar vi ut det från datorn och trycker sedan ‘Enter’ för att starta om datorn.
När datorn startat om kommer vi mötas av en svart skärm med grå text. Här finns en rad som säger:
ubuntuserver login:
(ubuntuserver är det datornamn vi valde i punkt 10.2 under installationen). Här skriver vi det användarnamn vi valde (under 10.3), till exempel ‘jonas’ och trycker sedan på ‘Enter’.Nu kommer en ny rad fram med texten
Password:
. Här skriver vi in det lösenord vi valde under installationen. Notera att Ubuntu inte kommer visa något alls när vi skriver in lösenordet. Skriv lösenordet och tryck på ‘Enter’. Är det rätt lösenord kommer vi loggas in på systemet och mötas av lite text och en kommandopromtjonas@ubuntuserver:~$
. Det är här vi skriver våra kommandon i Linux.
Uppdatera Ubuntu Server
Notera att vi visar kommandoprompten som |
Det är alltid bra att ha ett uppdaterat system, så vi loggar in på vår ubuntuserver och skriver följande kommando:
Här kommer vi få frågan om ett lösenord, [sudo] password for jonas:
(jonas är det användarnamn vi loggat in med i det här fallet). Vi skriver in samma lösenord som vi använder för att logga in på Ubuntu med vårt användarkonto. Kommandot apt update
går ut på internet och hämtar listan över de senast tillgängliga versionerna av programpaket. Denna kommer användas för att se vilka paket som kan uppdateras på vårt system. För att utföra uppdateringen kan vi använda kommandot apt upgrade
eller apt dist-upgrade
. Skillnaden på dem är att dist-upgrade
också uppgraderar linuxkärnan och inte bara systemkomponenterna. Ibland vill vi inte uppgradera linuxkärnan, så det är bra att det finns möjlighet att välja bort uppgradering av den (med upgrade
).
När kommandoprompten kommer tillbaka skriver vi följande kommando för att uppdatera vårt system:
sudo
är ett kommando som ger oss tillfällig administratörsbehörighet i Ubuntu, det behöver vi eftersom vi skall uppgradera den installerade programvaran. apt
är kommandot för att hantera programpaket. dist-upgrade
betyder att vi vill uppgradera alla installerade paket och slutligen -y
betyder att vi svarar ‘ja (yes)’ på alla frågor. Vill vi se vad Ubuntu kommer installera och välja om vi skall göra uppgraderingen eller inte så tar vi bort -y
. Då får vi svara själva på de frågor som kommer.
När uppdateringen är klar vill vi starta om systemet, det gör vi med kommandot reboot
:
Hitta hjälp i Ubuntu
I Linux finns hjälpen alltid nära, nästan alla kommandon vi använder har en manualsida skriven för sig. I den hittar vi information om vad kommandot gör och vilka parametrar vi kan använda tillsammans med kommandot. Vi hittar också information om vem som har skrivit kommandot och hur vi kan skicka buggrapporter om vi upptäcker fel.
För att läsa en manualsida använder vi kommandot man
. Vi tittar på manualsidan för kommandot man
:
Om du inte har kommandot |
Manualsidorna är uppdelade i olika sektioner där manualsidor som handlar om samma område samlas.
| 1 | Executable programs or shell commands | | 2 | System calls (functions provided by the kernel) | | 3 | Library calls (functions within program libraries) | | 4 | Special files (usually found in /dev) | | 5 | File formats and conventions, e.g. /etc/passwd | | 6 | Games | | 7 | Miscellaneous (including macro packages and conventions), e.g. man(7), groff(7) | | 8 | System administration commands (usually only for root) | | 9 | Kernel routines [Non standard] |
Det kan finnas fler man-sidor med samma namn i systemet. Till exempel printf
som dels kan användas för utmatning i Bash och dels som en funktion i programmeringsspråket C.
Här är vi på kommandoraden och skriver printf
:
Här är källkod skriven i programspråket C som också använder printf
, fast en annan printf
. Här är det en funktion som finns i standardbiblioteket för programspråket C.
Skulle vi skriva in ovanstående program skrivet i programspråket C och vill kompilera (göra det körbart) det till ett program behöver vi installera ett paket som heter gcc
. Det paketet innehåller en kompilator för programspråket C:
Nu kan vi kompilera programmet:
-o hello
anger vad vi vill att filen skall heta, och hello.c
anger vilken fil vi vill läsa in. Sedan kör vi det genom att skriva programmets namn:
Vi använder ./
innan programmets namn för att berätta för Bash att programmet finns i den här katalogen, där vi befinner oss. ./hello
betyder alltså: kör programmet hello som finns i katalogen där jag befinner mig just nu.
För att hitta rätt man-sida för den printf
vi vill läsa om kan vi ange vilken sektion vi vill använda:
Vi kan också skriva sektionen efter namnet, som i printf.1
och printf.3
.
Hitta kommandon
När vi inte vet vilket kommando vi skall använda kan vi söka efter ett lämpligt kommando med man -k
:
Vi kan också använda kommandot apropos
för att söka efter kommandon:
Vill vi veta vad ett kommando används till kan vi använda kommandot man -f
:
Vi kan också använda kommandot whatis
istället för man -f
:
De flesta kommandon kan också ge hjälp själva, genom att vi använder argumentet -h
, eller ibland --help
:
Manualsidan för ett kommando visar också ofta bra hjälp:
För att komma tillbaka från manualsidan till kommandoprompten trycker vi på bokstaven |
Användare och grupper
I Ubuntu finns användarkontona i systemet i två filer, dels i filen /etc/passwd
som innehåller användarkontot och dels i filen /etc/shadow
där lösenordet för användarkontot lagras.
Skapa användare
Med kommandot useradd
skapar vi användare i systemet. För att skapa en användare med användarnamnet jonas skriver vi:
När vi skapar användaren jonas skapas en post i filen /etc/passwd
som ser ut så här:
I filen /etc/shadow
skapas följande:
I filen /etc/group
skapade en grupp för användaren jonas:
Och slutligen skapade en hemkatalog som heter /home/jonas/
, i den katalogen skapades några filer som kommer ifrån katalogen /etc/skel/
.
Om vi vill ange var hemkatalogen för användaren skall skapas använder vi flaggan --home-dir KATALOG
, vill vi ange vilken kommandotolk användaren skall använda anger vi det med flaggan --shell KOMMANDOTOLK
. För att skapa användaren lisa med hemkatalogen /home/lotta/
och kommandotolken /bin/bash
skriver vi:
- -d /home/lotta/
-
anger vilken hemkatalog användaren skall ha.
- -m
-
anger att vi vill skapa hemkatalogen till användaren.
- -s /bin/bash
-
anger att användaren skall få kommandotolken bash.
Vi har inte skapat något lösenord för användarna vi skapat, så de kan inte logga in än. För att sätta lösenord för en användare använder vi kommandot passwd
:
När vi skriver in lösenordet syns inget på skärmen och vi skriver in lösenordet två gånger (vid New password och Retype new password). |
Användarna kan själva byta sitt lösenord när de loggat in genom att använda kommandot passwd
och sätta det lösenord de vill ha. Användaren root kan sätta lösenord för alla användare genom att använda kommandot sudo passwd ANVÄNDARNAMN
.
Det finns ett kommando som heter |
Ta bort användare
När vi tar bort en användare från systemet kan vi inte återskapa användaren eller dennes filer igen, om vi inte har backup. Så var noga med vilken användare du väljer att ta bort. |
För att ta bort en användare från systemet använder vi kommandot userdel
. För att ta bort användaren jonas (användarnamnet måste naturligtvis existera i systemet för att kunna tas bort) skriver vi:
När vi tar bort en användare är det bara användarkontot som raderas, användarens hemkatalog finns kvar i filsystemet. För att ta bort en användare och radera hennes hemkatalog samtidigt lägger vi till flaggan --remove
till kommandot:
Det kan vara en bra idé att göra en säkerhetskopia på våra användares hemkataloger innan vi raderar dem. Kommandot |
Om vi glömde bort flaggan --remove
när vi tog bort användarkontot finns hemkatalogen för användaren kvar i filsystemet. Vi kan använda kommandot rm
för att radera katalogen:
Kommandot |
Filen /etc/passwd
Det är i filen /etc/passwd
systemet lagrar informationen om användarkonton. Varje rad i filen innehåller ett användarkonto och det finns sju fält på varje rad:
Nedan följer en beskrivning av fälten ovanför, värdet inom parantes är motsvarande vad som står i raden (exemplet som börjar med ubuntu) ovanför.
- användarnamn
-
Det användarnamn som användaren loggar in med. (ubuntu)
- lösenord
-
Här finns normalt ett x som betyder att lösenordet finns i filen
/etc/shadow
. (x) - användar-id
-
Användar-id är det numeriska id som användarkontot har. I Ubuntu är alla användar-idn under 1000 systemkonton och alla användar-idn från 1000 och uppåt är vanliga användarkonton. (1000)
- grupp-id
-
Fältet anger vilken primär grupp användaren tillhör. Varje användare i systemet måste tillhöra en primär grupp, vill vi att de skall ingå i flera grupper är det filen
/etc/group
som hanterar dem. (1000) - kommentarsfält
-
Kommentarsfältet kan användas till vad som helst. Ubuntu lagrar informationen om fullständigt namn här. Undvik att använda kommatecken (,) i kommentarsfältet, eftersom kommatecken är fältseparatorn i filen. (ubuntu user)
- hemkatalog
-
Fältet för hemkatalog anger vilken katalog som är användarens hemkatalog. När en användare loggar in i systemet är det hemkatalogen som är startpunken. Normalt finns alla användares hemkataloger under katalogen
/home/
(/home/ubuntu) - kommandotolk
-
Fältet anger vilken kommandotolk en användare skall få efter att hon loggat in. (/bin/bash)
Alla användare i systemet måste tillhöra en primär grupp. När användaren loggar in sätts den primära gruppen och alla filer som användaren skapar kommer automatiskt kopplas till den gruppen. Som standard kommer Ubuntu skapa en primär grupp som har samma namn som användarkontot. Skapar vi användaren kalle kommer det också skapas en grupp som heter kalle som användaren kalle kommer få som primär grupp, om vi inte väljer något annat. Alla användarkonton i Ubuntu kan också tillhöra en, flera eller ingen sekundär grupp. De sekundära grupperna används för att ge rättigheter för användaren att komma åt filer, program och kataloger. |
Byta användarnamn
Vi kan byta användarnamnet för en användare med kommandot usermod
. För att byta användarnamn på jonas till lasse skriver vi:
Byta primär grupp för en användare
Med kommandot usermod
kan vi byta användarens primära grupp. För att byta primär grupp för användaren jonas till gruppen video skriver vi:
Vi kan också använda ett grupp-id (GID) när vi väljer vilken grupp användaren skall ha som primär grupp:
Alla grupper i systemet finns i filen /etc/group
som vi kan visa med kommandot cat
:
Vi kan också använda kommandot getent
för att visa grupper i systemet:
Uppdatera kommentarsfältet för en användare
Med kommandot usermod
kan vi uppdatera kommentarsfältet för en användare. Vi skriver så här för att uppdatera fältet för användaren jonas:
Om vi tittar i filen /etc/passwd
nu så kommer det stå:
Byta hemkatalog för en användare
Med kommandot usermod
kan vi byta hemkatalog för en användare. För att byta hemkatalog för användaren jonas till /tmp/
skriver vi:
När vi byter hemkatalog för en användare ändras referensen till hemkatalogen i filen /etc/passwd
, den gamla hemkatalogen finns kvar under katalogen /home/
eller där den var. Om vi vill flytta innehållet i den gamla hemkatalogen till den nya använder vi flaggan -m
till kommandot:
Byta kommmandotolk för en användare
För att byta kommandotolk för en användare använder vi kommandot chsh
. För att byta kommandotolk för användaren jonas till /bin/bash
skriver vi:
De kommandotolkar vi kan använda defineras i filen /etc/shells
. I den filen står alla kommandotolkar som är godkända att använda. Användaren root kan ändra kommandotolk för alla användare och en användare kan bara ändra sin egen kommandotolk.
Om vi av någon anledning vill inaktivera inloggning för en användare kan vi sätta användarkontots kommandotolk till /sbin/nologin
, vilket innebär att användaren kan logga in men får ingen giltig kommandotolk så hon loggas ut direkt igen. Ett bättre alternativ för att inaktivera användarkonton är att låsa kontot med kommandot sudo passwd -l ANVÄNDARNAMN
. För att låsa upp kontot igen använder vi kommandot sudo passwd -u ANVÄNDARNAMN
.
Användare kan själva byta kommandotolk med kommandot chsh
, men den kommandotolk de väljer måste finnas med i filen /etc/shells
som anger vilka kommandotolkar som är tillåtna i systemet. Det är bara användaren root som kan byta kommandotolk till vad som helst för användarkonton. Om vi loggar in som användaren jonas och försöker byta kommandotolk till /bin/banan
ser det ut så här:
Filen /etc/shadow
Lösenorden för användarkonton i systemet finns i filen /etc/shadow
som bara är läsbar för användaren root. Lösenordsfilen har en säkerhetskopia i filen /etc/shadow-
. Om vi tittar i filen så hittar vi flera rader som ser ut så här:
Varje rad i filen /etc/shadow
består av nio olika fält som åtskiljs av kommatecken (:
) enligt följande:
- Användarnamn
-
Det användarnamn som användaren loggar in med.
- Lösenord
-
Det krypterade lösenordet, uppbyggt enligt mönstret
$kryptering$salt$krypterat lösenord$
. De olika krypteringsalgoritmerna som kan användas är:$1$
som betyder att lösenordet är hashat med md5-algoritmen,$2$
och$2a$
som betyder att lösenordet är hashat med blowfish,$5$
som betyder att lösenordet är hashat med sha-256 och slutligen$6$
som betyder att lösenordet är hashat med sha-512. Ett lösenord som börjar med ett utropstecken (!
) innebär att användarkontot är låst och inte går att logga in med. - Senast ändrat
-
Anger vilket datum (antal dagar efter den 1 januari 1970) som lösenordet senast ändrades. Står det en nolla (0) här betyder det att användaren måste byta lösenord nästa gång hon loggar in. Är fältet tomt innebär det att systemet inte tar hänsyn till att lösenordet måste bytas efter ett visst antal dagar.
- Lägsta tid
-
Anger hur många dagar användaren måste ha ett lösenord innan hon får byta det igen. En nolla (0) eller ett tomt fält här innebär att inställningen är avstängd.
- Högsta ålder
-
Anger hur många dagar användaren får ha samma lösenord innan hon behöver byta det. När de här antalet dagarna har passerats kommer systemet be henne byta lösenord när hon loggar in. En nolla (0) eller ett tomt fält innebär att funktionen är inaktiverad. Notera att om högsta ålder är lägre än minsta ålder kan användaren inte byta lösenord alls.
- Lösenordsvarning
-
Anger hur många dagar innan lösenordets upphörande en användare skall varnas för detta. En nolla (0) eller ett tomt fält innebär att funktionen är inaktiverad.
- Inaktiveringsperiod
-
Anger hur många dagar efter att ett lösenord har upphört som det fortfarande skall gå att logga in på systemet med det. Efter den här perioden låses kontot helt och en administratör måste låsa upp det. Ett tomt fält anger att funktionen är inaktiverad.
- Utgångsdatum
-
Anger ett datum, räknat från den 1 januari 1970, som ett användarkonto skall upphöra. På det här datumet kommer användaren inte längre kunna logga in i systemet med sitt lösenord. Ett tomt fält anger att funktionen är inaktiverad.
- Reserverat fält
-
Det här fältet är reserverat för framtida användande.
Om vi har två användare i vårt system som har samma lösenord, säg att lösenordet är hemligt kommer de få samma hashade lösenord när lösenordet körs genom en hashningsalgoritm. Genom att använda salt i lösenordet kommer de hashade lösenorden se olika ut, även om lösenorden är samma. Så om vi kommer åt filen /etc/shadow
kommer vi inte kunna se att två användare har samma lösenord i systemet.
Titta på följande exempel:
Resultatet av båda körningarna blir samma, vi får svaret a5cd101aef627c48222e6def444a36d7
båda gångerna. Om vi istället lägger till salt kommer det se ut så här:
Vi har fortfarande samma lösenord (hemligt), men salt skiljer sig (salt och peppar) vilket resulterar i helt olika resultat. Eftersom vi vet vilket salt vi skall använda för att generera hashen kommer det fungera att logga in - om vi har angett rätt lösenord.
Hantera lösenord och konton
För att ändra ett lösenord för en användare använder vi kommandot passwd
:
Ovanstående kommando kommer byta lösenord för användaren jonas. Alla användare kan byta sina egna lösenord genom att använda kommandot passwd
när de loggat in. Användaren root kan byta lösenord för alla användare i systemet genom att använda kommandot passwd ANVÄNDARNAMN
.
För att tillfälligt låsa ett användarkonto för inloggning kan vi använda kommandot sudo passwd -l ANVÄNDARNAMN
(-l
för lock). För att låsa upp kontot igen använder vi kommandot sudo passwd -u ANVÄNDARNAMN
(-u
för unlock). Ett användarkonto som låses upp har samma lösenord som det hade när det låstes. Det är bara användaren root som kan låsa och låsa upp användarkonton i systemet.
För att hantera policyn för lösenord använder vi kommandot chage
. Det första vi provar är att hämta ut informationen för det användarkonto vi loggat in med genom att skriva sudo chage -l jonas
(där jonas är användarnamnet vi loggar in med):
Ovanför ser vi att lösenordet senast ändrades den 19:e januari 2013 (last password change), lösenordet upphör aldrig att gälla (password expires), vi har ingen inaktivitetsperiod på lösenordet (password inactive), användarkontot har ingen upphörandedag (account expires), vi kan byta lösenordet när vi vill (minimum number of days between password change), det får gå 99999 dagar (nästan 274 år) innan vi måste byta lösenord igen (maximum number of days between password change) och när vi börjar närma oss de 99999 dagarna kommer vi börja få varningar om att vi behöver byta lösenord från sju dagar innan (number of days of warning before password expires).
Om vi vill ändra datumet till julafton 2014 för senaste gången vi bytte lösenord på ett användarkonto skriver vi:
För att se att datumet ändrades använder vi kommandot sudo chage -l jonas
.
För att ställa in ett utgångsdatum för användarkontot använder vi flaggan -E
. Vi anger datumet i antalet dagar räknat från den 1 januari 1970 eller ett datum i formatet ÅÅÅÅ-MM-DD. Värdet -1 gör att kontot aldrig upphör att gälla. Vill vi ställa in att ett användarkonto skall upphöra att gälla den sista december 2013 skriver vi följande kommando:
För att kontrollera att det blev inställt skriver vi:
Om vi vill bestämma hur många dagar en användare skall ha sitt nya lösenord innan hon får byta det använder vi flaggan -m
tillsammans med antal dagar. Värdet noll (0) anger att användaren får byta lösenord när hon vill.
Vill vi bestämma hur många dagar en användare får använda sitt lösenord innan det är dags att byta igen använder vi flaggan -M
tillsammans med antalet dagar. Värdet -1 inaktiverar funktionen.
Och för att sätta hur många dagar innan lösenordet upphör att gälla som användaren skall få en varning om att hon måste byta lösenord varje gång hon loggar in använder vi flaggan -W
tillsammans med antal dagar.
Kontrollera att användardatabasen är korrekt
Med kommandot pwck
kan vi kontrollera att användardatabasen är korrekt. Kommandot pwck
kontrollerar att vi har rätt antal fält, unika och godkända användarnamn, korrekta grupptillhörigheter, korrekt primär grupp, en hemkatalog som existerar, en fungerande kommandotolk, att användare i /etc/passwd
-filen finns i /etc/shadow
-filen, att vi har lösenord i /etc/shadow
-filen och att vi inte har bytt våra lösenord i framtiden (vilket är ett tecken på att klockan varit felaktig, eller att någon manipulerat med filerna). Vi kör kommandot pwck
:
Här ser vi att användarkontona ftp och avahi-autoipd har en hemkatalog som inte finns. Eftersom det är systemanvändare så spelar det ingen roll.
Att bli en annan användare
Ibland kan vi vilja bli en annan användare. Det kan till exempel vara när vi vill felsöka eller testa om en specifik användare kan komma åt en katalog eller läsa en fil. För att bli en annan användare behöver vi ha rättighet att använda kommandot sudo
. Vi anger användarnamnet vi vill bli och sedan -i
som är en parameter till kommandot sudo
som gör att vi kommer logga in som användaren för att få med alla inställningar hon har. Här blir vi användaren jonas:
Vi kan också använda kommandot su
för att bli en annan användare, då skulle det se ut så här:
Grupper
Grupper i Ubuntu finns i filen /etc/group
. Filen är en ren textfil och består av gruppinformation på en rad, separerad av fyra fält:
- Gruppnamn
-
Gruppens namn.
- Lösenord
-
Det krypterade lösenordet för gruppen (används sällan).
- Grupp-ID
-
Det numeriska värde som identifierar gruppen i systemet (GID).
- Användarlista
-
En lista med de användare som ingår i gruppen, varje användarnamn är separerad med ett kommatecken (
,
).
En grupp defineras så här:
För att skapa en ny grupp använder vi kommandot groupadd
, vi skapar gruppen elever:
För att ta bort en grupp använder vi kommandot groupdel
. Vi kan inte ta bort en grupp som någon användare har som primär grupp (finns i användarkontot i filen /etc/passwd
).
För att byta namn på en grupp använder vi kommandot groupmod
. Vi testar detta genom att skapa gruppen elever igen:
Vi kontrollerar att gruppen finns i filen /etc/group
:
Kommandot grep
används för att hitta reguljära uttryck (mönster) i texter och filer. Här använder vi det för att hitta elever i filen /etc/group
.
Om vi inte får tillbaka kommandoprompten när vi använder kommandot |
Nu byter vi namn på gruppen elever till students:
Vi kontrollerar att ändringen genomfördes:
För att lägga till en användare i en grupp använder vi kommandot gpasswd
:
Användaren måste logga ut och in igen för att få den nya grupptillhörigheten.
För att ta bort en användare från en grupp använder vi kommandot gpasswd
:
Om vi vill ta reda på vilka grupper en användare tillhör kan vi använda kommandot groups
. För att se vilka grupper användaren jonas tillhör skriver vi:
För att ta reda på vilka användare som tillhör en grupp använder vi kommandot getent
. För att visa användarna i gruppen students skriver vi:
Filrättigheter
Filrättigheter handlar om åtkomstkontroll till filer och kataloger för användare. Vilka användare får läsa filen? Vilka användare får skriva till och radera filen? Vilka användare får visa innehållet i en katalog? Det är inte alla filsystem som stödjer filrättigheter, men filsystemen ext4 och xfs som är de vanligaste i Linux har stöd för filrättigheter. Från Microsoft Windows kanske du känner till FAT32 och NTFS som är de filsystem vi använder i Microsoft Windows. NTFS har stöd för rättigheter i filsystemet, FAT32 har det inte.
I Linux finns det tre rättigheter:
- (r)ead, för att användare skall kunna läsa en fil
- (w)rite, för att användare skall kunna skriva till en fil, eller radera den
- e(x)ecute, för att användare skall kunna köra filen (starta programmet)
e(x)ecute har en speciell funktion för kataloger, om rättigheten är satt så får användaren visa filerna i katalogen.
Kom ihåg: read, write och execute |
Vi börjar med att skapa en tom fil (som vi döper till filer
) och visar den med kommandot ls
:
Den här delen skall vi titta på nu, för det är den som anger filrättigheterna: -rw-r--r--
. Det första tecknet (-
) anger att det är en vanlig fil vi ser. Så vi får kvar rw-r--r--
. Det är tre grupper: ägaren (user), gruppen (group) och andra (other). Var och en har tre av tecknen var, så här: rw- | r-- | r--
. Läser vi rättigheterna blir det ägaren av filen har läs- (r) och skriv- (w) rättighet, gruppen har läsrättighet (r) och andra har läsrättighet (r).
Vem är ägare av filen och vilken grupp tillhör filen? Vi tittar på kommandot ls -l
igen:
Det står jonas jonas
där, den första jonas
anger att jonas äger filen och den andra jonas
anger att filen tillhör gruppen jonas.
Vi läser raden igen: användaren jonas har läs- och skrivrättighet, gruppen jonas har läsrättighet och de användare som inte är jonas och inte tillhör gruppen jonas har läsrättighet till filen.
För att ändra rättigheterna på en fil använder vi kommandot chmod
. För att ge ägaren (u) rättighet att köra filen (eXecute) skriver vi:
För att ge gruppen (g) skrivrättighet (w) skriver vi:
För att ta bort läsrättigheten (r) för andra (o) skriver vi:
Vi kan kombinera dem i ett och samma kommando, så här skriver vi för att ta bort körrättigheten (x) från ägaren (u), ge gruppen (g) läs- och skrivrättigheter (rw) och ta bort läs- och körrättigheter (rx) för andra (o):
När vi använder +
och -
sätter vi, eller tar bort rättigheter oavsett vad vi har för rättigheter på filen sedan tidigare. Om ägaren av filen har rw-
och vi skriver chmod u-w
kommer ägaren ha rättigheten r--
efteråt.
För att sätta exakta rättigheter, oavsett vad vi har sedan tidigare, använder vi =
:
Nu kommer ägaren ha läs- och skrivrättigheter, gruppen har läsrättighet och andra har läsrättighet. Oavsett vilka rättigheter filen hade innan. I det här fallet sätter vi också samma rättighet på gruppen och andra (r), vilket kan förkortas:
Vi kan också använda oktala tal för att sätta rättigheterna enligt följande:
| 0 | Ingen rättighet (-) | | 1 | Kör (execute, x) | | 2 | Skriv (write, w) | | 4 | Läs (read, r) |
Dessa kan vi kombinera, så skriv (2) och läs (4) blir 6. Kör (1), skriv (2) och läs (4) blir 7. För att sätta rättigheterna med siffror måste vi ange alla tre grupperna (ägaren, gruppen och andra) i samma kommando:
755 är samma som om vi hade skrivit u=rwx,g=rx,o=rx
(eller den kortare varianten: u=rwx,go=rx
). Vi kan inte ta bort, eller lägga till, en specifik rättighet med siffror (som till exempel u+x
). Vill vi sätta samma rättigheter på en hel katalog och alla filer under den använder vi -R
(för recursive):
För att en användare skall kunna visa filerna i en katalog måste användaren ha rättigheten x på katalogen. Antagligen genom att användaren äger katalogen, tillhör gruppen eller har x genom andra-rättigheten. Har användaren läsrättighet på en katalog kan användaren läsa filer i en katalog, om hon vet namnet på filen. Lämpligast är ju att användaren har både läs- (r) och kör- (x) rättigheten.
För att byta ägare av en fil, eller katalog, använder vi kommandot chown
. Notera att det bara är root som kan byta ägare på en fil, så vi måste använda kommandot sudo
. För att göra användaren kalle till ägare av filen filer skriver vi:
För att byta ägare på en katalog och alla filer i katalogen skriver vi:
För att byta grupp på en fil, eller katalog, använder vi kommandot chgrp
. För att sätta gruppen till elever på filen filer skriver vi:
För att byta grupp på en katalog och alla filer i katalogen använder vi -R
(för recursive) och skriver:
Vi kan också använda kommandot chown
för att byta ägare och grupp i samma kommando:
Eller för en katalog och alla filer i katalogen:
Processhantering
Processer och deras identitet
I Linux får varje process som startas ett eget process id, som kallas PID. Den första PID som skapas är PID 1 och är i princip alltid processen init.
För att se vilken den högsta PID vi kan skapa i systemet är, tittar vi i filen /proc/sys/kernel/pid_max
:
Hantera processer
För att se vilka processer som är igång i systemet använder vi kommandot ps
. Det kan till exempel se ut så här:
I exemplet ovanför ser vi att vi har två processer igång: bash och ps. Bash är den kommandotolk vi kör i systemet, kommandoraden. Ps är kommandot vi använde för att se vilka processer som vi har igång, ps är alltså också igång när vi kör kommandot. PID anger vilket id processen har, TTY är vilken terminal processen körs på, TIME anger hur länge processen körts och CMD anger vilket kommando som körs.
TIME anger inte hur länge en process har körts i klocktid, utan i CPU-tid. Alltså hur länge processen har använt processorn.
Kommandot ps aux
visar alla processer som körs i systemet, av alla användare inklusive systemets egna processer.
Kommandot pstree
visar processlistan i en trädstruktur och vi kan se vilken process som startat en annan. Kommandot pstree
utan argument visar de processer som körs i vår terminal, vill vi se alla processer i systemet skriver vi pstree –a
.
Kommandot top
visar processerna interaktivt. För att avsluta top
trycker vi på tangenten q
. Vill vi ha färger och lite fler funktioner kan vi installera programmet htop
:
Starta sedan programmet genom att ange kommandot htop
. Avsluta genom att trycka på tangenten q
.
Kommandot pidof
visar vilken PID en process har. Till exempel pidof bash
. Kommandot används mest i skript där vi behöver veta om en process är igång eller inte.
Trevliga processer
Om vi vill starta en process med en annan prioritet än standard (0) använder vi kommandot nice
. Kommandot nice
gör att en process kan få företräde till processortid och vi bestämmer hur mycket, eller lite, företräde processen skall få genom att sätta nice till olika nivåer. Noll (0) är standard och ges till alla processer som startas. Därifrån kan vi ge processen högre prioritet genom att sätta nice till en lägre siffra, ner till -20 som är den högsta prioriteten vi kan ge en process. Vi ger processen en lägre prioritet genom att sätta en högre nice, upp till 19. Så -20 är högsta prioritet och 19 är lägsta. Noll (0) är standard. En process som har prioriteten 19 kommer enbart köras när ingen annan process i systemet vill använda processorn.
Om vi till exempel vill starta programmet top med den lägsta prioriteten (19) skriver vi:
När vi tittar i kolumnen NI i top ser vi att processen körs som nice 19. Väljer vi en högre siffra (20 och uppåt) kommer processen få 19, som är den lägsta prioriteten vi kan ge en process. Värden under noll (0) kan vi inte sätta om vi inte är användaren root. Det lägsta värdet vi kan sätta är -20, försöker vi sätta ett lägre värde än så får vi automatiskt värdet -20. Om vi inte anger något värde till nice kommer processen få värdet 10:
Med kommandot renice kan vi ändra prioritet på befintliga processer, sådana som redan är igång i systemet. För att ändra prioritet på processen med PID 2664 från 0 till 4 skriver vi:
Vi kan sätta nice på alla processer för en specifik användare genom att ange argumentet –u
:
Här ändrar vi alla processer som tillhör användaren jonas till prioriteten 4 från att ha varit 0. Användaren root kan ändra prioritet på processer hur hon vill. En användare i systemet kan bara sänka sin prioritet. Om användaren sänker sin prioritet på sin process från 0 till 10 kommer hon bara kunna sänka den ännu mer (11, 12, …) men inte höja den (9, 8, …) även om processens prioritet var högre innan.
Bakgrundsprocesser
Om vi skall köra ett kommando som kommer ta tid kan vi välja att köra det programmet i bakgrunden. När vi startar ett program på kommandoraden lägger vi till &
i slutet av kommandot för att köra det i bakgrunden, ett exempel:
Där [1]
anger vilket bakgrundsjobb det är och 28237 anger vilket process-id (PID) processen fick. Vi kan lista bakgrundsjobb med kommandot jobs
.
För att ta fram jobbet igen använder vi kommandot fg
. Om ett jobb har jobb-id 1 skriver vi fg 1
. Har vi flera jobb igång väljer vi helt enkelt vilket jobb vi vill ta fram med kommandot fg
genom att ange jobbets id: fg 3
. Om vi redan har startat en process på kommandoraden och vi vill lägga det som ett bakgrundsjobb trycker vi på tangenterna CTRL
och z
samtidigt.
Då pausar vi processen och kan välja att fortsätta köra det som ett bakgrundsjobb med kommandot bg
. Pausar vi flera processer väljer vi vilken process vi vill köra som bakgrundsjobb med kommandot bg
och jobbets id, till exempel: bg 2
. Om vi lagt ett jobb i bakgrunden med kommandot bg
och vill avsluta det använder vi kommandot kill
. Vi kan ta reda på processens PID och använda kommandot kill
med PID:en, eller så anger vi vilket jobbnummer vi vill avsluta. Jobbnumret anges med ett procenttecken (%
) och jobbnumret:
Vill vi använda till exempel SIGKILL (-9) på jobbet skriver vi:
Att använda screen
Ibland är det användbart att starta ett program på en linuxmaskin och låta det fortsätta köras även när vi loggat ut från maskinen. Det enklaste sättet att lösa detta är med kommandot screen
. Kommandot screen
är inte installerat som standard, utan vi får börja med att installera det i systemet med hjälp av kommandot apt
:
För att starta ett program med screen
börjar vi kommandoraden med screen
och sedan kommandot vi vill köra:
Vi startar top med screen. För att avsluta top trycker vi på q
på tangentbordet. När vi avslutar top kommer också screen avslutas, eftersom vi startade top med screen.
Vi kan också starta screen
utan att köra ett kommando, då skriver vi helt enkelt screen
på kommandoraden:
När vi startat en session med screen
kan vi går ur screen
, men fortfarande köra kommandot i systemet, genom att hålla inne tangenten CTRL
och trycka på tangenten a
och sedan på tangenten d
för att komma ut till vår terminal igen. Vi kommer få en rad liknande denna på kommandoraden:
Vilket betyder att screen
och alla kommandon vi kör i screen
fortfarande körs i systemet. För att återansluta till sessionen skriver vi screen -r
. När vi kör kommandon i screen
kommer de fortsätta köras i systemet även om vi loggar ut från det. Detta är användbart när vi vill köra en längre process, men inte vill vara inloggade i systemet under tiden det körs. Med argumentet -list
kan vi se alla screen som körs i systemet just nu:
Det här är bara en bråkdel av vad kommandot screen
klarar av att göra, för mer information läser vi manualsidan för kommandot: man screen
.
Att använda tmux
Tmux används på samma sätt som screen
. Det är mycket en smaksak vilken av screen
och tmux
man gillar. Till stora delar gör de samma sak.
För att köra tmux
behöver vi installera paketet tmux
:
Sedan kan vi starta tmux
genom att skriva:
Kommandon till tmux ges genom att vi trycker på CTRL
och bokstaven b
samtidigt, C-b
. Därefter anger vi kommandot vi vill ge. För att detacha vår tmux-session, så att vi kommer ut ur den men den fortfarande kör i bakgrunden använder vi C-b d
. För att återansluta till sessionen skriver vi kommandot tmux attach
.
Vi kan också skapa flera fönster i tmux (de syns i raden längst ned) genom att trycka C-b c
(för create). Hoppar mellan fönster gör vi genom att använda C-b n
(för next).
c-b t
visar en klocka med aktuell tid.
Hur Linux hanterar processer
Vi kan skicka signaler till processer i Linux, signalerna är styrkommandon som processen kan fånga upp (beroende på om utvecklaren har skrivit programkod som lyssnar på dem) och vi använder dem ofta för att stänga ner processer, eller helt enkelt tvångsavsluta dem.
Det finns en mängd olika signaler vi kan använda, några av de vanligaste är:
- SIGTERM
-
Avslutar en process. Signalen ber processen stänga ner sig på ett korrekt sätt, precis som om vi hade valt att avsluta ett program.
- SIGKILL
-
som försöker avsluta processen utan att ta hänsyn till något alls. Processen får ingen möjlighet att stänga filer som är öppna, eller frigöra minne som den använt.
För att se alla signaler vi kan använda i Linux kan vi skriva kommandot man signal
och manualsidan för kommandot kill
har lite information också: man kill
. För att skicka signaler kan vi använda kommandot kill
:
Om vi vill avsluta flera processer som heter samma sak, till exempel top
kan vi använda kommandot killall
. Med killall
anger vi inte processernas PID, utan deras namn.
För att avsluta alla processer som heter top
skriver vi:
Vi kan naturligtvis skicka andra signaler till processerna än standardsignalen SIGTERM genom att ange signalen till kommandot:
Användaren root kan avsluta alla användares processer. En vanlig användare kan enbart avsluta sina egna processer. Om vi vill avsluta alla processer som körs av användaren jonas skriver vi:
Arbeta med text
Att arbeta med Linux innebär att vi kommer jobba mycket med att redigera textfiler. Vi kommer ändra i konfigurationsfiler, vi kommer skriva skript och vi kommer dokumentera vårt system. Därför behöver vi kunna hantera en textredigerare. Det finns egentligen tre textredigerare som används idag och vilken som blir ens favorit är högst personligt:
- vi eller vim
-
Vi(m) är en ganska krånglig texteditor innan man blir vän med den. Fördelen med att kunna vi(m) är att den finns installerad i så gott som varje UNIX-baserat system. Grundkunskaper i vi(m) är således värdefullt oavsett om vi sitter med Linux, macOS eller BSD för att nämna några.
vi
är originalet ochvim
(Vi IMproved) är en förbättrad version avvi
. Det är oftavim
man menar när man pratar omvi
. - nano
-
En enkel texteditor som är snabb att komma igång med. Funktionaliteten är ungefär som Notepad i Windows och många nybörjare gillar nano.
- emacs
-
En avancerad textredigerare som kan göra mycket mer än att bara redigera text. En del säger att Emacs är ett helt eget operativsystem.
vi(m)
Vi har två olika lägen: command mode och insert mode. I command mode kan vi ge vim kommandon som att hoppa till början av raden, lägg till text på raden, ta bort raden och så vidare. I insert mode ändrar och skriver vi in texten vi vill ha in i filen. För att komma till command mode trycker vi på tangenten ESC
på tangentbordet och för att komma till insert mode så vi kan skriva in text trycker vi på bokstaven i
(för insert) när vi är i command mode. Vi kan också ge kommandon till vi på den nedersta raden på skärmen, dit kommer vi när vi är command mode och skriver kolon (:
). Efter kolon-tecknet kan vi skriva det eller de kommandon vi vill utföra.
Det kan vara svårt att förstå hur vi avslutar vi. Tryck på |
Om vi inte har vim
installerat använder vi kommandot apt
för att installera:
| i | Sätt in text framför markören |
| a | Sätt in text efter markören |
| / | Söka i filen, till exempel: /jonas
söker efter jonas i filen. Tryck på n
för att komma till nästa sökträff. |
| x | Ta bort tecknet under markören |
| 0 | Flytta markören till början av raden |
| $ | Flytta markören till slutet av raden |
| o | Skapa en ny rad under den du står på |
| O | Skapa en ny rad över den du står på |
| dd | Ta bort raden du står på |
| d$ | Ta bort allt från markören till slutet av raden |
| d0 | Ta bort allt från markören till början av raden |
| u | Ångra (undo) |
| :12 | Hoppa till rad 12. |
| :w | Spara filen |
| :q | Avsluta vi |
| :q! | Avsluta vi utan att spara ändringar i filen |
| :wq | Spara filen och avsluta vi |
| ZZ | Spara filen och avsluta vi |
När vi är i insert mode står det -- INSERT --
längst ner på skärmen. För att komma ut ur insert mode (när vi kan skriva text i filen) trycker vi på tangenten ESC
.
Det finns en manual för vim inbyggd, använd kommandot :help
för att visa den. Kommandot :q
avslutar manualen.
Det är en bra idé att få koll på textredigeraren vim då den finns installerad i princip i alla UNIX-baserade system. Det är inte alltid vi kommer kunna installera vår föredragna textredigerare på system vi kommer i kontakt med, så det är bra att kunna grunderna i vim.
Kommandot vimtutor
startar en lär dig vim-utbildning. Gå igenom den så kommer du kunna det du behöver kunna.
Saknar du vimtutor
behöver du installera paketet vim-runtime
:
nano
Editorn nano fungerar som de texteditorer vi är vana med som till exempel Notepad i Microsoft Windows. Kommandon till nano ges med CTRL
-tangenten och en bokstav. Längst ner på skärmen ser vi bland annat ^X Exit
, vilket betyder att vi skall hålla in CTRL
-tangenten och trycka på bokstaven x
samtidigt. En del kommandon i nano skrivs som M-d
, där M är meta vilket är ALT
-tangenten på en PC-dator.
| ^G
| Visar hjälp för nano, vi avslutar hjälpen genom att trycka på bokstaven q
|
| ^W
| Söker i filen |
| ^O
| Sparar filen |
| ^X
| Avslutar nano |
Om vi saknar nano i vårt system kan vi installera det med kommandot apt
:
Emacs
Vi startar Emacs genom att skriva emacs
på kommandoraden. För att avsluta Emacs håller vi in CTRL
och trycker på bokstaven x
, vi fortsätter hålla in CTRL
och sedan trycker vi på c
. I Emacs skrivs det här som C-x C-c
där C
betyder CTRL
.
| C-x C-c
| Avsluta Emacs |
| C-s
| Söka |
| C-g
| Avbryt |
| M-x tetris
| Spela Tetris |
| C-h t
| Starta Emacs tutorial |
För att installera emacs använder vi kommandot apt
:
Det finns också ett emacs
-paket att installera, det är den grafiska versionen som kräver att vi har en grafiskt skrivbordsmiljö installerad. Om vi använder en textbaserad server är det bättre att installera den textbaserade Emacs (emacs-nox
), eftersom den grafiska kommer installera paket för skrivbordsmiljön också.
Reguljära uttryck (regex)
Reguljära uttryck, regular expressions (eller regex, regexp) på engelska, är mönster som vi använder för att hitta en delmängd av en text. Säg att vi vill visa alla användarkonton som börjar med bokstaven a i vårt linuxsystem, det kan vi göra enkelt genom att skriva kommandot grep ^a /etc/passwd
. ^
betyder börjar med och a
är bokstaven a helt enkelt. I det här fallet blir det, visa mig alla rader som börjar med bokstaven a i filen /etc/passwd. Viktigt att känna till är att reguljära uttryck är skiftlägeskänsliga (skillnad på stora och små bokstäver).
Vi kan använda en del specialtecken för att gruppera och matcha mönster:
| [ ] | Matchar på det som är i paranteserna. Bokstäver och siffror, antagligen tillsammans eller enskilt. Notera att matchningen är skiftlägeskänslig! (Stora och små bokstäver) |
| - | Skapar en serie av tecken, används ofta för 0-9, A-Z och a-z. |
| ^ | Matchar på början av en rad, om vi vill matcha alla rader som börjar med bokstaven L skriver vi ^L
. Om tecknet finns i []
som till exempel [^a]
betyder det att vi inte skall matcha på det tecknet. |
| $ | Matchar på rader som slutar med. Som till exempel Linux$
skulle matcha alla rader som slutar med Linux. |
| . | Matchar vilket (okänt) tecken som helst. Till exempel L...x
|
| * | Matchar tecknet ingen eller fler gånger. Till exempel L.*x
, där .
anger ett okänt tecken och *
att vi vill matcha inget eller flera okända tecken. |
| ( ) | Kombinerar flera mönster att matcha på. |
| | | Matchar på vänster eller höger, används ofta tillsammans med ( )
|
Vi börjar med att skapa filen exempel.txt
som finns här nedanför. Skriv in texten i en fil och spara den i ditt linuxsystem. Vi kommer använda den som exempel för att titta på hur vi kan använda reguljära uttryck.
Med kommandot grep
kan vi arbeta med reguljära uttryck, vi börjar med ett första exempel:
Här letar vi efter allt som har bokstaven r följt av ett a eller ett e. Har vi texten reguljär, raket, dragkrok, orkestrera kommer det matcha uttrycket r[ae]
.
Vi tittar på ett liknande exempel, där vi använder s[ik]
som uttryck:
Vill vi hitta alla förekomster av bokstaven k i en fil skriver vi:
Om vi vill hitta alla förekomster av bokstaven k, men inte dem där k följs direkt av ett a använder vi mönstret k[^a]
:
Titta på svaren vi får från de två ovanstående exemplen, k
och k[^a]
.
Om vi vill hitta alla förekomster av siffrorna 0, 1, 2, 3, 4, 5, 6, 7, 8 och 9 kan vi skapa en range av dem genom att skriva [0-9]
(alla siffror från noll (0) till och med nio (9)):
Om vi vill visa alla rader i filen där vi inte har bokstäver (A-Z) använder vi grep -v [A-Za-z] exempel.txt
. Notera hur vi anger A-Za-z eftersom vi behöver matcha på både stora och små bokstäver. Prova också att ta bort -v
och se vad skillnaden blir.
Om vi vill hitta alla rader i filen som börjar med bokstaven M skriver vi:
Eftersom vi enbart matchar på stora m (M) och vill få fram de rader som börjar med små m också skriver vi ^[Mm]
:
Matcha rader som börjar med bokstaven M eller bokstaven m.
Ibland är vi mer intresserade av att matcha rader som slutar med någonting. För att matcha alla rader som slutar med ux
i filen exempel.txt
skriver vi mönstret ux$
:
Slutligen vill vi ibland matcha på rader som börjar med och slutar med någonting. För att matcha alla rader som börjar med bokstaven s
och slutar med ux
använder vi mönstret ^s.*ux$
. .
anger vilket tecken som helst (det vill säga - det kan matcha vilket tecken som helst) och *
betyder inget eller flera av det som står till vänster. .*
blir alltså inget eller flera av vilket tecken som helst:
Omstyrning och rör
I vår kommandotolk (BASH) finns tre olika strömmar för in- och utmatning av information:
- Standard in (0, stdin)
- Standard out (1, stdout)
- Standard error (2, stderr)
Bash använder som standard Standard Out (stdout) för att skicka utmatning från kommandon. Ibland vill vi ändra detta så utmatningen till exempel lagras i en fil istället. Säg att vi visar innehållet i en katalog och vi vill ha den listan i en textfil som vi kan arbeta vidare med istället, då använder vi >
för att styra om standard out till filen:
Här listar vi katalogens innehåll (filer och kataloger) med kommandot ls -l
, men istället för att få listan på skärmen skickas utmatningen till filen ls.txt
. >
fångar upp det som skickas till standard out och styr det vidare till en fil. Ett annat sätt att fånga upp standard out är att skriva 1>
, vilket betyder att det är stdout vi vill jobba med. stdin har 0 och stderr har 2.
Exemplet ovanför gick bra för att vi listade en katalog som finns (den katalog vi befinner oss i). Om vi provar att visa filerna i en katalog som inte finns kan det se ut så här:
Hade vi skickat stdout till filen ls.txt hade den varit tom, men vi hade fått ett felmeddelande:
Att filen ls.txt
blir tom beror på att vi inte kan lista några filer i en katalog som inte finns och att vi får ett felmeddelande på skärmen och inte i filen beror på att felmeddelandet skrivs till standard error (stderr). Vill vi fånga upp stderr använder vi 2>
och det kan se ut så här:
Här fångar vi upp både standard out (1>) och standard error (2>) och skriver dem till två olika filer. När vi tittar på innehållet i filen ls.txt
är det tomt. Katalogen vi försökte lista finns inte, så inget kommer skrivas till filen ls.txt
. När vi tittar på innehållet i filen ls.fel
får vi fram felmeddelandet som tidigare skrevs ut på skärmen. Det beror på att vi nu fångat upp stderr med 2>
och skickat utmatningen till filen ls.fel
.
Nu skapar vi en fil som vi döper till namn.txt
, i filen skriver vi in följande namn:
Spara filen och avsluta din textredigerare. Nu skriver vi:
Inget konstigt händer, filens innehåll skrivs ut som vi skrev den i textredigeraren. Låt oss nu sortera filen i alfabetisk ordning:
Namnen i filen skrivs nu ut i alfabetisk ordning. Här använder vi omdirigeraren för stdin, <
, för att läsa innehållet i filen namn.txt
och skicka in den i kommandot sort
. Eftersom kommandot sort
vill skicka sin sorterade data till standard out hamnar listan på skärmen. Om vi vill spara den sorterade listan i en ny fil dirigerar vi om stdout till en fil så här:
Ingenting händer på skärmen, men tittar vi i katalogen så skapades en fil namn.sorterad.txt
. Med kommandot cat
kan vi visa innehållet i filen:
Den sorterade listan med namn skickades till filen namn.sorterad.txt
istället för skärmen.
När vi använder >
skriver vi över innehållet i filen varje gång. Ibland vill vi istället lägga till saker i slutet av en fil, då fungerar det inte att använda >
som skriver över filen. Vi använder två stycken >
-tecken istället: >>
. >>
gör att det vi dirigerar om till filen läggs till i slutet av filen:
Vi kan också använda rör (pipes) för att skicka data vidare till andra kommandon. Det kan till exempel vara att vi har en katalog med många filer så att kommandot ls -l
gör att massor av text skrollar förbi på skärmen. Då kommer kommandot less
till hjälp. less
gör att när skärmen är fylld med text pausar less
utmatningen tills vi tryckt på mellanslag och då får vi en ny sida med text. Vi skriver ls -l /usr/bin/ | less
för att se hur det fungerar. Pipe-tecknet (det lodräta strecket, |
) fångar upp stdout från komamndot ls
och skickar in det till stdin för kommandot less
:
Varför kan vi inte använda <
istället? <
fungerar bara på filer, inte på kommandons utmatningar (stdout). Så för att fånga upp stdout från ett kommando och skicka det till ett annat kommandos stdin använder vi pipetecknet (|
), för att hämta information från en fil och skicka den till ett kommandos stdin använder vi <
-tecknet. Vi skulle kunna skriva så här, om vi ville slippa pipe:
Här visar vi en detaljerad lista över alla filer och kataloger som finns i katalogen /usr/bin/
och sparar listan till filen filer
. Sedan använder vi kommandot less
för att öppna och visa filen filer
som vi precis skapade. Att använda pipe för detta är mycket effektivare och bättre, om vi inte också vill spara utmatningen till en fil så klart.
Vi kan kombinera flera pipe om vi behöver det. Om vi till exempel vill visa alla filer i en katalog, sortera listan baklänges och visa listan med less skriver vi:
Skulle vi istället vilja ha den baklängessorterade listan till en fil skulle vi skriva så här:
Det går alltså att kombinera flera <
. >
, >>
och |
på en och samma kommandorad.
Jobba mer med text
Vi börjar med att skapa filen namn.txt
med följande innehåll:
Vi vill hitta unika namn i den filen och vänder oss därför till kommandot uniq
:
Här ser vi att listan med namn blir kortare, men vi har fortfarande dubletter av namn kvar. Det beror på att uniq
behöver ha dubletterna efter varandra. Vi kan använda kommandot sort
för att sortera listan alfabetiskt och sedan använda uniq
för att visa unika namn:
Nu fungerade det bättre, men varför använda kommandot uniq
när sort
redan har möjlighet att visa unika:
Om vi vill visa listan med unika namn i filen baklänges (Z-A) lägger vi till -r
:
Hur många namn vi har i listan kan vi visa med kommandot wc
som bland annat kan räkna rader (lines) i en fil:
Hur många unika namn har vi i listan i filen? Vi kombinerar kommandot sort
och kommandot wc
för att räkna ut det:
Om vi vill sortera filer med siffror får kommandot sort
lite problem, vi skapar filen nummer.txt
med följande innehåll:
Om vi använder kommandot sort
för att sortera numren i filen kommer vi få följande resultat:
Det blir rätt, men ändå fel. sort
gör helt rätt - börjar med siffran 1 och går vidare med 2 och så vidare. Men vi vill ju ha numren i ordning efter värde. Om vi lägger till -n
för numeric till kommandot sort
får vi:
Nu ser det bättre ut. Vill vi ha numren i baklänges ordning (högst till lägst) använder vi -r
och skriver sort -n -r nummer.txt
.
Användarkonton i Ubuntu finns i filen /etc/passwd
. Det hade varit trevligt om den listan kunde vara i bokstavsordning, så vi använder kommandot sort
:
Varför inte bara visa användarnamnen, istället för all information? Med kommandot cut
kan vi splitta en rad som har avgränsare (till exempel :
) och välja vilket fält vi vill ha:
Här berättar vi att vår avgränsare är :
, vilket fungerar bra för filen /etc/passwd
som ser ut så här:
cut -d ":"
anger alltså att vår avgränsare (delimiter) är :
, -f1
anger att vi vill ha det första fältet (i det här fallet blir det det användarnamnen) och /etc/passwd
anger vilken fil vi vill jobba med.
Om vi vill veta vilka kommandotolkar som används av våra användare kan vi titta på fält sju (7) i filen /etc/passwd
, där står det vilken kommandotolk som användaren skall logga in med. Användaren jonas nedanför använder kommandotolken /bin/bash
:
För att hämta ut alla användares kommandotolkar skriver vi:
Det blir en ganska lång lista och vi vill egentligen bara veta vilka unika kommandotolkar användarna använder, så låt oss använda sort -u
också:
Hur många användarkonton har vi i systemet? Kommandot wc
kan räkna åt oss:
wc -l
räknar rader (lines), wc -c
räknar antal tecken i en fil och wc -w
räknar antalet ord (words) i en fil.
Flera kommandon på samma rad
Ibland vill vi köra flera kommandon på en och samma rad. Varför sitta och vänta på att ett kommando skall köras klart innan vi kan skriva nästa? Det finns två sätt att göra detta, antagligen med ett semikolon (;
) eller med två och-tecken (&&
). Skillnaden på dem är att &&
inte kör nästa kommando om föregående inte lyckades. Detta visas bäst med ett exempel:
Första gången vi kör kommandot lyckas det båda gångerna. Andra gången stavar vi fel på date (vi skriver dat) och får ett felmeddelande och andra kommandot (date) körs. Sista gången gör vi samma misstag (stavar fel på date) och får ett felmeddelande.
Det andra date
-kommandot körs inte, eftersom vi använder &&
. Om vi istället vill köra ett annat kommando om det första inte lyckas (motsatsen till &&
) kan vi använda dubbla pipe-tecken (||
):
Eftersom date
fungerar första gången kommer vi inte skriva ut texten som kommer efter. I andra försöket skriver vi date utan e (dat) och det blir fel, därför skrivs texten ut.
I de exempel vi har haft ovanför använder vi två kommandon, vi kan naturligtvis använda flera kommandon. Som exempel kan vi konfigurera och bygga ett program från källkod direkt från en och samma kommandorad:
Här är det viktigt att vi använder &&
, vi vill ju inte bygga programmet om det inte gick att konfigurera och än mindre vill vi installera ett sådant program i vårt system.
Ibland blir raderna med kommandon vi skriver långa, då kan vi använda backslash (\
-tecknet) för att fortsätta mata in kommandon på nästa rad innan vi kör alltihopa:
Samma sak skulle kunna skrivas som:
Kommandotolken Bash
En kommandotolk, skal (shell), används för att ge datorn instruktioner om vad den skall göra. Idag är det vanligaste sättet att arbeta med en dator med ett grafiskt gränssnitt, GUI (Graphical User Interface). I ett GUI klickar användaren med en muspekare på vad användaren vill att datorn skall göra. I ett skal skriver användaren sina kommandon i en textbaserad miljö, som kallas CLI (Command Line Interface). Ett skal är alltså ett kommandoradsbaserat gränssnitt mot användaren.
Den första kommandotolken för UNIX skrevs av Steven Bourne 1974. Kommandotolken hette Bourne Shell och är kanske mer känd som sh. Bourne Shell har satt standarden för hur kommandotolkar skall se ut och fungera, bland annat har vi fått kommandoprompten $
från Bourne Shell.
Bash är troligen den vanligaste kommadotolken som används i operativsystemet Linux. Bash, som är en förbättring av Bourne Shell, är en förkortning av Bourne Again Shell. Bash är resultatet av GNU-projektets arbete med att förbättra Bourne Shell. Bash är helt POSIX-kompatibelt. I exemplet nedanför ser vi hur Bash är startad och väntar på kommandon från användaren.
- jonas
-
är användarnamnet på den användare som är inloggad
- ubuntu
-
är namnet på den dator användaren är inloggad på
- tildetecknet (
~
) -
anger vilken katalog användaren är i, tilde är en förkortning för användarens hemkatalog och dollartecknet är kommandoprompten, det är efter kommandoprompten användaren kan skriva sina kommandon.
Vi kan arbeta med Bash interaktivt, det vill säga vi skriver våra kommandon direkt på kommandoraden, eller genom att skriva skript. Ett skript är en samling av instruktioner som sparats i en vanlig textfil. När vi kör textfilen med Bash kommer den utföra de instruktioner textfilen innehåller. Vi kommer börja att jobba med Bash interaktivt för att lära oss hur Bash fungerar och vad vi kan göra med Bash. När vi kommit en bit på vägen börjar vi skapa våra första skript.
När Bash startas letar den efter ett par konfigurationsfiler som den läser in (om de finns) och kör. Ordningen på vilka filer den läser in är:
- Om filen
/etc/profile
finns läses den in. Här finns systemglobal konfiguration. Filen läser in filen/etc/bash.bashrc
. Filen läser också in alla filer som finns i katalogen/etc/profile.d/
och har filändelsen.sh
. - Om filerna
~/.bash_profile
och/eller~/.bash_login
finns kommer Bash läsa in den första filen den hittar av dessa. Om de inte finns kommer~/.profile
läsas in av Bash. I Ubuntu är det~/.profile
som skapas för varje användare och används.~/.profile
läser in filen~/.bashrc
. Filen~/.bashrc
i sin tur läser in filen~/.bash_aliases
om den finns.
Vill vi skapa egna systemglobala miljövariabler eller funktioner för Bash är rekommendationen att skapa filen /etc/profile.d/custom.sh
och lägga allt där. Detta för att vi skall undvika att nästa uppdatering av paketet bash skulle kunna skriva över våra ändringar i filerna.
Om vi vill skapa egna variabler och funktioner för vår egen användare är ~/.bashrc
en bra plats att göra det i. Lägg till variabler och funktioner i slutet av den filen. Är det alias vi vill lägga till är filen ~/.bash_aliases
en bra plats att lägga in dem i.
.bash_profile
(och .bash_login
, .profile
) läses bara in när du loggar in i systemet. Startar du en ny instans av Bash när du är inloggad redan, till exempel genom att skriva bash
på kommandoraden, läser Bash enbart in filen .bashrc
.
När du loggar ut läser Bash filen ~/.bash_logout
om den finns. Där kan vi till exempel lägga in kommandot clear
så att Bash raderar allt på skärmen innan vi loggar ut.
Kommandoprompten
Kommandoprompten styrs av två miljövariabler: PS1
och PS2
. PS1
är den kommandoprompt du normalt ser (se exemplet ovanför), medan miljövariabeln PS2
används för den kommandoprompt som visas på andra raden. PS2
är normalt ett >
-tecken.
Exempel:
Vi kan ändra kommandopromptarna så de blir som vi vill.
I tabellen nedanför visar vi ett par av de styrkoder vi kan använda för att anpassa vår kommandoprompt. |
Nu vill vi skapa en kommandoprompt som ser ut så här:
Först har vi användarnamnet på inloggad användare (jonas), sedan kommer datorns namn (ubuntu). I parantesen visas hur mycket klockan är (08:06:10) och slutligen kommer vilken katalog vi befinner oss i (tmp). För att skapa en kommandoprompt som ser ut så här skriver vi:
| Styrkod | Förklaring |
| ======== | ========== |
|\a |ASCII bell (ett kort pip) |
|\d |Datumet i veckodag månad datum-format, till exempel: mån dec 25 |
|\e |ASCII escape tecknet |
|\h |Datornamnet (hostname) fram till den första punkten |
|\H |Datornamnet (hostname) |
|\j |Antalet processer (jobb) som hanteras av kommandotolken |
|\1 |Vilken terminal är vi inloggade på? |
|\n |Newline, ny rad |
|\r |Carriage return, radbrytning |
|\s |Skalets namn |
|\t |Klockan i 24-timmarsformat (TT::SS) |
|\T |Klockan i 12-timmarsformat (TT::SS) |
|@ |Klockan i 12-timmarsformat med am/pm |
|\u |Användarnamnet på inloggad användare |
|\v |Versionen på Bash (3.1) |
|\V |Versionen på Bash med patchnivå (3.1.17) |
|\w |Nuvarande katalog (/usr/share) |
|\W |Basnamnet på nuvarande katalog (share) |
|! |Historynumret på det kommando som kommer att utföras |
|# |Nummer som visar hur många kommandon du utfört i det nuvarande skalet. |
|$ |Om användaren är UID 0 (root) visas ett #
-tecken, annars visas ett $
-tecken. |
|\nnn |Visar tecknet som motsvaras av det oktala numret nnn. |
|\ |Ett backslash-tecken |
|[ |Påbörja en sekvens med icke utskrivningsbara tecken. |
|] |Avsluta en sekvens av icke utskrivningsbara tecken. |
Vi kan ange färger för vår kommandoprompt, vi måste dock tänka på att se till att escapa (vilket görs med backslash \
, som också kallas escapetecknet) färgkoderna korrekt - annars fungerar det inte. Leta upp den färg du vill använda i tabellen för färgkoder här nedanför och skriv den som \[\033[0;32m\]
(väljer grön färg), allt som kommer efter det kommer skrivas ut i grönt. För att byta färg igen skriver du den nya färgkoden och sedan vad du vill skriva ut.
Ett exempel:
Vill du få tillbaka din vanliga prompt igen kan du logga ut och in igen, eller skriva:
För att göra ändringarna permanenta (dvs de aktiveras varje gång du loggar in) lägger du till dem i filen |
|Färg |Färgkod |Färg |Färgkod |
| ====== | ======= | ========= | ======= |
|Svart |0;30 |Mörkgrå |1;30 |
|Röd |0;31 |Ljusröd |1;31 |
|Grön |0;32 |Ljusgrön |1;32 |
|Brun |0;33 |Gul |1;33 |
|Blå |0;34 |Ljusblå |1;34 |
|Lila |0;35 |Ljuslila |1;35 |
|Turkos |0;36 |Ljusturkos |1;36 |
|Ljusgrå |0;37 |Vitt |1;37 |
Förutom miljövariablerna |
Reserverade ord
Bash har, precis som andra kommandotolkar, reserverade ord. Ord som används för speciella ändamål av Bash. I Bash kan du använda orden som variabelnamn (det går inte i alla kommandotolkar), men du bör undvika det för att slippa bli förvirrad när fel uppstår.
| ! | case | coproc | do
| done | elif | else | easc
| fi | for | function | if
| in | select | then | until
| while | { } | time | [[ ]]
Alias i Bash
Många kommandon använder sig av argument och ibland kommer vi på oss själva att alltid använda samma argument till kommandot. Vore det inte ganska smart att kunna skapa ett nytt kommando som gör att vi slipper skriva in kommandot och argumenten varje gång? Genom att skapa ett alias för ett kommando kan vi anropa kommandot med argument utan att själva behöva skriva argumenten. Ett sådant kommando kan vara ls
som vi ofta använder med argumentet -l
för att visa en detaljerad lista över filerna i en katalog.
Vi skapar ett alias för att visa en katalog med detaljer för filerna i den (kommandot ls -l
). Aliaset döper vi till ll
:
Nu kan vi skriva ll
istället för att skriva ls -l
varje gång vi vill visa en detaljerad lista över filer i en katalog.
För att ta bort ett alias använder vi kommandot unalias
. För att ta bort aliaset ll
som vi precis skapade skriver vi:
Om vi vill lista alla alias vi har tillgängliga skriver vi bara alias
:
Ett alias kan heta samma sak som kommandot, vi skulle alltså kunna skapa aliaset ls
som ger oss kommandot ls med argumentet -l
(ls -l
):
Vi kan skapa våra alias direkt på kommandoraden eller spara dem i vår ~/.bash_aliases
-fil som finns i vår hemkatalog. Om vi skapar våra alias i .bash_aliases
kommer de alltid vara tillgängliga för oss när vi loggar in. För att skapa ett alias i filen .bash_aliases
öppnar vi filen med en texteditor och skriver in aliaset i filen, precis som vi gjorde på kommmandoraden ovanför:
Om vi inte sparar våra alias i filen .bash_aliases
kommer alla alias att försvinna när vi loggar ut.
Historik i Bash
Bash håller en historik på vilka kommandon vi använt. Hur många kommandon Bash skall komma ihåg bestäms av miljövariabeln HISTSIZE
, vill vi se vad den är satt till kan vi skriva:
Alla kommandon i historiken sparas i filen .bash_history
i användarens hemkatalog, om vi inte ändrat miljövariablen HISTFILE
som används för att ange vilken fil historiken skall sparas i.
Vi kan söka i historiken med !
-tecknet.
Kommandot !d
letar efter det senaste kommandot som använts som börjat med bokstaven d
, vi skrev date
precis innan så det är date
som är senast använt. Om vi fortsätter och testar, kan vi skriva:
Eftersom vi nu anger !da
kommer inte kommandot dir
köras igen, istället letar Bash i historiken efter det senaste kommandot som började på da och kör kommandot date
. Efter det skriver vi !di
för att köra kommandot dir
igen.
Vill vi se vilket kommando history
kommer köra innan den kör kommandot skriver vi:
I fallet ovanför kommer ett !d
att köra kommandot date
.
Dubbla utropstecken (!!
) kör det senaste kommandot igen:
Om vi vill köra ett kommando som vi körde för n gånger sedan skriver vi !-n
:
Vill vi se hela historiken skriver vi history
.
Vill vi se de senaste fem (5) kommandona i historiken skriver vi:
Vill vi köra kommandot 1220 (date
) igen skriver vi:
Vill vi ta bort ett kommando från historiken använder vi kommandot history -d nummer
:
Vill vi tömma hela historiken använder vi kommandot history -c
:
Flera kommandon på samma rad
Ibland vill vi köra flera kommandon på en och samma rad. Varför sitta och vänta på att ett kommando skall köras klart innan vi kan skriva nästa? Det finns två sätt att göra detta, antagligen med ett semikolon (;
) eller med två och-tecken (&&
). Skillnaden på dem är att &&
inte kör nästa kommando om föregående inte lyckades.
Detta visas bäst med ett exempel:
Första gången vi kör kommandot lyckas det båda gångerna. Andra gången stavar vi fel på date (vi skriver dat) och får ett felmeddelande och det andra kommandot (date) körs. Den sista gången gör vi samma misstag (stavar fel på date) och får ett felmeddelande.
Det andra date
-kommandot körs inte, eftersom vi använder &&
. Om vi istället vill köra ett annat kommando om det första inte lyckas (motsatsen till &&
) kan vi använda dubbla pipe-tecken (||
):
Eftersom date
fungerar första gången kommer vi inte skriva ut texten som kommer efter. I det andra försöket skriver vi date utan e (dat) och det blir fel, därför skrivs texten ut.
I de exempel vi har har här ovanför använder vi två kommandon, vi kan naturligtvis använda flera kommandon. Som exempel kan vi konfigurera och kompilera ett källkodspaket direkt från en kommandorad:
Här är det viktigt att vi använder &&
, vi vill ju inte kompilera paketet om det inte gick att konfigurera och än mindre vill vi installera ett sådant paket i vårt system.
Ibland blir raderna med kommandon vi skriver långa, då kan vi använda backslash (\
-tecknet) för att fortsätta mata in kommandon på nästa rad innan vi kör alltihopa:
Samma sak skulle kunna skrivas som:
Omdirigering och rör
Innan vi börjar med omdirigeringar måste vi ha klart för oss att Bash arbetar med tre olika standarder för in- och utmatning av information:
- Standard in (stdin, 0)
- Standard out (stdout, 1)
- Standard error (stderr, 2)
Siffrorna 0, 1 och 2 kommer vi snart tillbaka till.
Bash använder som standard Standard Out (stdout) för att skicka utmatning från kommandon. Ibland vill vi ändra detta så utmatningen lagras i en fil. Säg att vi visar innehållet i en katalog och vi vill ha den listan till en textfil som vi kan arbeta med. Vi skriver:
Här listar vi katalogen med kommandot ls -l
, men utskriften kommer inte visas på skärmen utan skickas vidare till en fil som vi kallar ls.txt
.
Vi skulle kunna skriva ls -l > ls.txt
också, eftersom Bash då tolkar >
som 1>
.
Om vi nu istället vill lista en katalog som inte finns kommer vi få ett felmeddelande:
Om vi nu skickar stdout till filen ls.txt
kommer filen ls.txt
vara tom, eftersom katalogen /tmp/a/
inte finns kan vi inte lista innehållet i katalogen.
Vi kommer få ett felmeddelande som ser ut så här:
Felmeddelanden från kommandon skickas till stderr och vi kan fånga upp stderr på samma sätt som vi gjorde med stdout.
Istället för att använda 1 (som vi gjorde för stdout) använder vi 2 (för stderr).
Vi tittar på ett exempel där vi skickar alla felmeddelanden till en fil som vi kallar ls.fel.txt
:
Nu fångar vi alltså upp stdout (1) till filen ls.txt
och stderr (2) till filen ls.fel.txt
.
Nu tittar vi på hur vi kan dirigera om stdin (för input). Vi börjar med att skapa en fil, som vi döper till namn.txt
, med följande innehåll:
När vi matat in alla namn sparar vi filen och avslutar vår textredigerare.
Nu använder vi kommandot cat
för att visa innehållet av filen:
Inget konstigt händer, filens innehåll skrivs ut som vi skrev den i textredigeraren. Låt oss nu sortera filen i alfabetisk ordning:
Namnen skrivs ut i alfabetisk ordning.
Här använder vi omdirigeraren för stdin, <
, för att läsa innehållet i filen namn.txt
och skicka innehållet till kommandot sort
.
Eftersom kommandot sort
vill skicka sin sorterade data till stdout hamnar listan på skärmen, om vi vill spara den sorterade listan i en ny fil dirigerar vi om stdout till en fil så här:
Ingenting händer på skärmen, men tittar vi i katalogen så skapades en fil: namn.sorterad.txt
.
Vi använder kommandot cat
för att visa innehållet:
Den sorterade listan skickades till filen namn.sorterad.txt
istället för skärmen.
När vi använder >
(ett tecken) skriver vi över innehållet i filen varje gång, ibland vill vi istället lägga till saker i slutet av en befintlig fil.
Då kan vi inte använda >
.
För att lägga till innehåll i en befintlig fil, utan att skriva över filen, använder vi två stycken >>
istället.
>>
gör att det vi dirigerar om till filen läggs till i slutet av filen:
Vi kan använda rör (eng. pipe) för att skicka data vidare till andra kommandon.
Du kan ha sett exempel på kommandon som ls -l | less
någon gång.
ls -l
visar en detaljerad lista över vad en katalog innehåller och den listan kan bli ganska lång om katalogen innehåller många filer, så genom att skicka utskriften från kommandot ls
till kommandot less
, som visar en skärmsida i taget, får vi en bättre översikt av listan.
Det är tecknet |
(pipe) som genomför det magiska här.
Pipe fångar upp stdout från kommandot ls
och skickar texten vidare till stdin för kommanot less
.
Nu provar vi det här i verkligheten:
Varför kan vi inte använda <
istället? <
fungerar bara för filer, inte på kommandons utmatningar.
Så för att fånga upp stdout från ett kommando och skicka det till ett annat kommandos stdin använder vi |
-tecknet, för att hämta innehållet från en fil och skicka det vidare till ett kommandos stdin använder vi <
-tecknet.
Vi skulle kunna skriva så här, om vi vill slippa använda pipe:
Visa en detaljerad lista över alla filer i katalogen och spara listan i filen filer.txt
, visa sedan filen filer.txt
med kommandot less
.
Att använda ett rör för ändamålet är betydligt effektivare än att gå via en fil.
Vi kan naturligtvis använda flera rör på en och samma rad om vi behöver det.
Om vi vill visa alla filer i en katalog, sortera listan baklänges och visa den med kommandot less
skriver vi:
Skulle vi vilja ha den baklängessorterade listan till en fil istället för skickad till kommandot less
skulle vi kunna skriva så här:
Det går alltså att kombinera flera av <
, >
och |
på en och samma kommandorad.
Jokertecken
När vi arbetar med filnamn och katalognamn, till exempel med kommandot ls
, kan vi använda jokertecken. Det finns tre jokertecken: +*+
, ?
och []
.
Det första jokertecknet är +*+
som betyder inget eller flera, vi använder +*+
när vi vet en del av, men inte hela, filnamnet. Vet vi början, något i mitten eller slutet av filnamnet? Vi tittar på ett exempel:
Först listade vi filnamn som börjar med bokstäverna xz (+xz*+
), sedan listade vi filnamn som slutar med bokstäverna xz (+*xz+
) och slutligen listade vi filnamn som innehåller bokstäverna xz (+*xz*+
).
Det andra jokertecknet är ?
som betyder exakt ett okänt tecken. Vill vi söka efter flera okända tecken får vi lägga till ett ?
-tecken för varje okänt. är det tre okända tecken blir det till exempel ???
.
I det första exemplet ovan visar vi alla filnamn som är fyra tecken långa, där de tre första är okända och det fjärde tecknet är ett e (???e
). I det andra exemplet visar vi alla filnamn som är fyra tecken långa, där det andra tecknet är bokstaven i
och det fjärde tecknet är bokstaven e (?i?e
).
Det tredje jokertecknet är egentligen två tecken: +[+
och +]+
. +[ ]+
används för att ange en uppsättning tecken. Om vi vill lista alla filer som börjar med a, b eller c i katalogen kan vi skiva +ls a* b* c*+
. Det är inte speciellt snyggt, men det fungerar. Prova att skriva +ls [abc]*+
istället, det gör samma sak. Om uttrycket mellan +[+
och +]+
börjar med ett utropstecken (!
) eller cirkumflex (^
) betyder det allt som inte matchar uttrycket. Vi kan till exempel lista alla filer utom de som börjar med bokstaven a, b eller c. Några exempel på hur vi använder detta:
Vi kan ange områden i våra sökningar istället för att ange ett specikt tecken. Om vi till exempel vill lista alla filer som börjar med någon av bokstäverna a till c skriver vi +ls [a-c]*+
. För att ange stora bokstäver skriver vi istället +ls [A-C]*+
och för siffror skriver vi +ls [0-9]*+
. För att lista alla filer som börjar med en liten eller en stor bokstav skriver vi +ls [A-Za-z]*+
.
Hur gör vi för att visa de dolda filerna med hjälp av jokertecken? Vi måste ange punkten (.
) först, sedan används jokertecken precis som med vanliga filer:
Skriva skript i Bash
Innan vi börjar skriva vårt första skript i Bash skall vi gå igenom ett par grundläggande saker. Skript kan skivas i många olika språk, nu använder vi Bash. Vi skulle lika gärna kunna skriva våra skript i csh, zsh, ksh eller någon annan kommandotolk. Vi kan skriva skript i Bash även om vi använder zsh som kommandotolk, och tvärtom. Skript är helt vanliga textfiler som innehåller information till datorn vad vi vill att den skall göra. Lite grann som ett recept: ta en deciliter mjöl, blanda ut det med en tesked salt, värm upp fyra deciliter mjölk och rör ner mjölet i det..
Trots att Linux inte använder filändelser för filer i filsystemet använder vi traditionellt filändelsen .sh
för bashskript. Du har säkert redan listat ut att .sh
är en förkortning för det engelska ordet shell. Den första raden i filen vi skapar för vårt skript måste ange vilken kommandotolk vi vill använda, detta eftersom användaren kanske kör skriptet under en helt annan kommandotolk som har ett annat programspråk.
För att ange att det är Bash vi vill använda skriver vi: +#!/usr/bin/env bash+
på den första raden i vår fil. Ibland stöter vi på +#!/bin/sh+
i skriptfiler. Tittar vi på filen /bin/sh
med kommandot ls -l /bin/sh
i filsystemet upptäcker vi att det är en länk till /bin/dash
. Inte alls samma kommandotolk som vi vill använda. Ganska ofta kommer vi stöta på +#!/bin/bash+
på den första raden i bashskript också, det är inte helt fel men vi bör undvika det eftersom bash
kan ligga någon annan stans i filsystemet hos den som kör vårt skript. Vi håller oss därför till +#!/usr/bin/env bash+
i våra skript.
Vi tittar på vårt skript så här långt:
Staket-tecknet (#
) används normalt för kommentarer, förutom just för denna rad där den anger vilken kommandotolk vi skall starta för att köra skriptet. Nu lägger vi till en rad i vårt skript så det faktiskt kan göra något:
Kommandot echo
innebär att Bash skall skriva ut något, i det här fallet texten Hej Bash!. Vi avslutar vårt skript på rätt sätt, det vill säga anropar kommandot exit
och anger ett exitvärde:
Ett skript som lyckats köra utan problem skall returnera exitvärdet noll (0), alla andra värden än noll (0) är felmeddelanden. Vi kommer tillbaka till detta med returvärden och exitvärden lite senare.
Nu är vårt skript färdigt, vi sparar filen och skriver chmod +x hello.sh
(om vi döpte skriptet till hello.sh
). Detta gör vi för att skriptet skall gå att köra utan att först anropa bash.
Om vi inte sätter executeflaggan (x) med chmod kan vi ändå köra vårt skript, om vi startar det med bash, så här:
Nu skall vi titta på lite miljövariabler i Bash. Kommandot printenv
visar vilka variabler som är satta i systemet och vad de innehåller:
Det finns en miljövariabel som heter USER
, den innehåller användarnamnet för den användare som är inloggad. Vi visar variabeln genom att skriva:
Innan vi skall använda variabeln i vårt skript skall vi ta och titta på skillnaden mellan tecknen "
och '
i Bash:
Om vi använder citattecken ("
) kommer variabeln expanderas, det vill säga - innehållet i den kommer att visas. Använder vi däremot apostrof-tecken ('
) kommer variabeln inte expanderas. Det är skillnaden mellan de två.
Nu öppnar vi vårt skript, hello.sh
, igen och ändrar lite i det:
Nu sparar vi filen och kör skriptet. Nu kommer skriptet att skriva ut Hej Jonas istället (om vårt användarnamn är jonas).
En viktig del av de skript vi skriver är kommentering. Kommentarer i skripten kommer hjälpa oss när vi kommer tillbaka till skriptet tre, eller sex månader sedan och inte längre minns hur vi tänkte när vi skrev det. Att kommentera vårt korta skript Hej Bash verkar kanske lite onödigt, men vi tittar ändå på hur vi kan skapa kommentarer i våra skript:
Nu sparar vi filen och kör skriptet. Det är ingen synlig skillnad från innan, det skriver fortfarande ut Hej jonas på skärmen (om vårt användarnamn är jonas). Med hjälp av +#+
-tecknet kan vi alltså skriva kommentarer i våra skript. Allt som kommer efter +#+
-tecknet, fram till radbrytningen, kommer att tolkas som en kommentar och ignoreras av Bash. Skriver vi ett +#+
-tecken i början av raden ignoreras hela raden. Skriver vi ett +#+
-tecken någon annanstans på raden ignoreras allt från tecknet fram till radbrytningen.
Vi bör alltid skriva bra kommentarer i våra skript. När vi tittar på skripten ett halvår senare kommer vi tacka oss själva för att vi kommenterade skripten. Hur väl insatta vi än känner oss i våra skript idag, kommer situtionen se annorlunda ut om ett par månader då vi sitter och funderar på varför vi har med det där konstiga i skriptet.
Variabler
För att kunna skapa användbara skript måste vi ha koll på variabler. En variabel är en plats i datorns minne som innehåller ett värde. Variabler deklareras innan de kan användas. I Bash behöver vi inte deklarera variabeln innan vi använder den, utan kan tilldela den ett värde direkt:
I exemplet ovanför deklarerar vi variabeln NAMN
och tilldelar den värdet jonas. Variabelnamnen i Bash skrivs traditionellt med stora bokstäver för att skilja dem från kommandon i skriptet. Variabler deklareras med sitt namn (NAMN
i exemplet ovanför) men refereras till som ${variabelnamn}
(som ${NAMN}
i exemplet ovanför).
Vi kan inte använda mellanslag mellan variabelnamnet, likamed-tecknet (=
) och värdet vi vill tilldela, några exempel:
Det är bara det sista kommandot i exemplet ovanför, VAR="jonas"
, som fungerar - de andra skapar felmeddelanden. Skall vi skapa riktigt fina skript bör vi använda declare
för att deklarera våra variabler. declare
har dessutom några flaggor som vi har nytta av ibland:
-a
för array (listor)-i
för integer (heltal)-p
för print (visa variabelns värde)-r
för read-only (variabeln går inte att ändra)-x
för export (variabeln exporteras)
Listor (array) och heltal (integer) kommer vi använda senare. Vi tittar på print, read-only och export så länge:
Print (-p
) visar variablens värde, det vi lagrat i variablen. Notera att vi inte använder ${NAMN}
här. Nu tittar vi på read-only:
I exemplet ovanför skapar vi en read-only variabel som vi döper till OS
, värdet för OS
sätter vi till Linux. Vi visar variabelns värde med hjälp av kommandot echo
. Sedan försöker vi ändra värdet till Windows, vilket Bash sätter stopp för.
Variabler som inte går att ändra (read-only) kallas för konstanta variabler eller bara kort: konstant.
Export (-x
) använder vi för att göra våra variabler tillgängliga utanför det skript som vi skapar dem i. Nu skapar vi skriptet export.sh
:
Vi sparar skriptet och skapar ett nytt skript som vi döper till import.sh
:
Lägg märke till att vi inte deklarerar variabeln DIST
i filen import.sh
. Det skall vi inte göra. Vi anropar också skriptet import.sh
från export.sh
genom att skriva bash import.sh
. Nu kör vi skriptet export.sh
:
Det fungerade ju ganska bra. export.sh
startas och anropar import.sh
, det ser vi på utskriften. Däremot visas inte värdet i variabeln DIST
i skriptet import.sh
, så vi ändrar i export.sh
:
Det vi gör är att vi exporterar variabeln DIST
med hjälp av flaggan -x
till declare
. Exporten sker till alla skal som startas från det vi kör just nu, när vi startar import.sh
med bash-kommandot i export.sh
kommer variabeln alltså att exporteras till Bash som startar import.sh
. Nu fungerar vårt skript som vi tänkt.
Istället för att använda declare -x
kan vi istället skriva export
. declare -x DIST="Ubuntu"
skrivs så här med export
: export DIST="Ubuntu"
.
Ibland kan det vara bra att ta bort sina variabler också, det gör vi med kommandot unset
. unset
är inget krångligt alls utan fungerar så att man skriver unset VARIABELNAMN
. Vi skapar ett skript för att visa hur det fungerar:
Nu sparar vi filen och kör den för att se vad som händer när vi använder unset
.
In- och utmatning
För att användaren skall kunna mata in svar och på så sätt påverka hur skriptet kommer köras behöver vi använda bashs inbyggda kommando read
. Med read
kan vi vänta på att användaren skall svara på en fråga innan vi fortsätter köra skriptet. Vi skriver ett enkelt skript (inmatning.sh
):
Vi sparar skriptet som inmatning.sh
och sätter körflaggan (chmod +x inmatning.sh
) på filen och testar skriptet. Det användaren matar in hamnar i variabeln USERNAME
, vi använder den variabeln för att skriva ut Hej ...
på raden efter inmatningen. Lade du märke till att du fick svara på raden under frågan? Det ser inte så bra ut, helst skulle vi vilja att användaren svarade direkt efter frågan. Det löser vi med en flagga till echo
, nämligen -n
:
Flaggan -n
till echo
innebär att echo
inte skapar en ny rad efter att den skrivit ut texten. Varför inte använda kommandot read
för detta istället? Vi tittar på flaggan -p
för kommandot read
:
Se där, det fungerar ju. Flaggan -p
(för prompt) till kommandot read
innebär att read
skall skriva ut något innan användaren matar in sitt svar. Variabeln som skall innehålla svaret skriver vi sist på raden med read -p
.
Hur gör vi om användaren inte svarar inom en tidsperiod, säg tre sekunder? Skall skriptet stå och vänta i all evighet då, eller skall vi gå vidare ändå med standardvärden? Naturligtvis har read
ett sådant val också, -t
. Tiden read
skall vänta mäts i sekunder. Vi tittar på ett exempel:
Nu kommer skriptet vänta i tre (3) sekunder innan det går vidare. Här är det lämpligt att lägga in ett standardvärde, om användaren inte matar in något:
Om användaren inte matar in sitt namn inom tre sekunder kommer variabeln USERNAME sättas till värdet Hemlig.
Slutligen skall vi titta på hur vi hanterar för långa inmatningar. Kommandot read kan begränsa hur många tecken vi skall läsa in från kommandoraden med hjälp av flaggan -n
. Vi vill inte ha längre namn än tio (10) tecken så vi begränsar användaren till det:
När användaren har matat in tio tecken, eller tryckt på RETUR, avbryts inmatningen och Dina tecken är … skrivs ut. Notera att det blir skönhetsfel om användaren matat in tio tecken, Dina tecken är … skrivs ut direkt efter det inmatade. En lösning på detta är att lägga till ett extra echo
på raden mellan read
och echo
i skriptet.
Om vi inte anger ett variabelnamn till read
kommer svaret användaren matar in att hamna i variabeln REPLY
:
Utmatningen sker med antagligen kommandot echo
, som vi använt hittils, eller med kommandot printf
som har fler funktioner för formatterad utskrift.
Några av specialtecknen för utmatning i printf
:
|Specialtecken | Förklaring |
| ================ | ============ |
| \b
| Backspace |
| \n
| Newline, skapa en ny rad |
| \t
| Tabb |
| \\
| Ett backslashtecken |
| \0n
| Visa ASCII-tecknet med koden n |
Vi testar printf
på kommandoraden:
Det där blev inte riktigt vad vi tänkte oss. Eftersom vi inte omsluter värdet vi tilldelar variabeln MENING
med citattecken blir utskriften felaktig, vi provar igen:
Nu fungerade det mycket bättre. %s
anger att vi vill skriva ut en sträng, strängen hittar printf
i variabeln vi anger efter printf
. Specialtecknet \n
skapar en radbrytning.
Vi tittar på hur vi kan hantera tal med %d
:
Med %d
kan vi inte skriva ut bokstäver, det är bara hela tal som fungerar. Vi skriver BRED=25
och försöker igen:
De två %%
-tecknen som kommer efter %d
är till för att skriva ut ett procenttecken (%
).
Räkna med bash - de fyra räknesätten
I det här avsnittet skall vi titta på hur vi kan räkna med de fyra räknesätten: addition, subtraktion, multiplikation och division i Bash.
Addition
Addition av två tal beräknas med plustecknet (+
). Vi kan använda kommandot let
för detta:
Vi kan också använda dubbla paranteser på det här viset:
Subtraktion
Subtraktion av två tal beräknas med minustecknet (-
), vi använder kommandot let
för detta:
Eller med dubbla paranteser:
Multiplikation
Multiplikation av två tal beräknas med *
, vi använder kommandot let
för detta:
Eller med dubbla paranteser:
Division och modulus
Division med heltal skapar en kvot och en rest. Eftersom vi bara kan räkna med heltal kan vi inte inte få fram decimalerna i våra uträkningar med division. Vi tar 5/2
som exempel, kvoten kommer bli 2.5
, men eftersom vi enbart kan räkna med heltal kommer kvoten från Bash bli 2
. 2 * 2 = 4
kvar har vi alltså 1
. För att få fram resten (1) använder vi oss av modulus som är ett procenttecken (%
): 5%2
ger oss 1
. Resten av heltalsdivisionen 5/2
är alltså 1
.
Vi använder kommandot let
för att få fram kvoten av 100 dividerat med 10:
Vi kan naturligtvis göra samma sak med dubbla paranteser:
Hur gör vi om divisionen inte går jämnt ut? Vi måste få fram resten, vilken vi får med hjälp av modulus (%):
Vad hände här? 100 går att dela med 13 sju gånger ( 13 * 7 = 91
). Kvar blir 9 (91 +9 = 100
).
Det finns flera olika sätt att räkna med decimala tal (flyttal) i Bash, vi skall titta på ett sätt vi kan använda. Kommandot bc
.
Vi börjar med att räkna ut 2.5*5
med decimaler:
Detta fungerar med addition, subtraktion och multiplikation. Även division fungerar, men vi måste använda scale
för att ange noggrannheten (precisionen) på antalet decimaler. Vi tittar på ett exempel:
Fem delat med två blir 2.5 och inte 2 som i exemplet ovanför. För att visa decimalerna använder vi scale
:
Genom att sätta scale=2
före uttrycket vi vill beräkna säger vi till bc
att vi vill visa talet med två decimalers noggrannhet. scale=1
ger oss en decimal, scale=4
ger oss fyra decimaler och så vidare.
Ofta vill vi lagra resultatet av en beräkning i en variabel för att kunna använda den senare i våra skript. För att göra detta använder vi $( )
på detta viset:
För division med scale
ser det ut så här:
Genom att ange flaggan -l
till kommandot bc
får vi maximal precision på decimalerna, ofta är det dock bättre att specifiera hur stor noggrannhet vi vill ha med scale
:
Villkor
Villkor använder vi för att skapa alternativ för skriptet, vad händer till exempel om programmet vi vill använda i skriptet inte finns?
Ett enkelt villkor skrivs så här:
Villkor för filer
Vi använder ofta villkor för att testa filer i början av skript. Finns filen vi vill läsa? Om den inte finns kommer skriptet inte fungera och bör avbrytas snarast. Kan vi skriva till en fil? om inte verkar det dumt att ens försöka.
| Villkor | Förklaring |
| ======== | ========= |
| -b
| Är filen en block device? |
| -c
| Är filen en character device? |
| -d
| Är filen en katalog (directory)? |
| -e
| Finns filen (exists)? |
| -h
och -L
| Är filen en länk (link)? |
| -r
| Är filen läsbar för vårt skript? |
| -s
| Finns filen och har den något innehåll? |
| -w
| Är filen skrivbar för vårt skript? |
| -x
| Är filen körbar för vårt skript? |
| fil1 -nt fil2
| Är fil1 nyare än fil2 (newer than)? |
| fil1 -ot fil2
| Är fil1 äldre än fil2 (older than)? |
Vi skriver ett exempel som visar hur det fungerar:
Ovanstående exempel testar om filen hemliginfo.dat
i katalogen är läsbar för vårt skript. Om den är det kommer texten Vi kan läsa filen. att skrivas ut. Nu är det kanske inte alltid det här vi vill testa, utan snarare vill vi testa om en fil går att läsa, om inte skall skriptet avbrytas. Vi använder utropstecknet (!
) för att göra om ett sant villkor till ett falskt. Ett villkor som uppfylls, till exempel att filen finns är sant. Ett villkor som inte uppfylls är falskt. Ett villkorsuttryck kan alltså bara resultera i en av två värden: sant eller falskt.
Ofta vill vi se om ett villkor inte är uppfyllt, till exempel om filen inte finns. I exemplet ovanför testade vi om filen hemliginfo.dat
var läsbar för skriptet, om filen fanns skulle vi skriva ut Vi kan läsa filen. Istället för att enbart skriva ut texten med kommandot echo
skulle vi kunna skriva hela vårt skipt mellan raden med if
och raden med fi
. Det här skulle bli ganska opraktiskt att underhålla, speciellt när vi egentligen bara ville se om filen var läsbar och om den inte var det skulle vi avbryta skriptet.
Vi ändrar skriptet så det ser ut så här:
Om filen finns och är läsbar för vårt skript kommer if-satsen resultera i att villkoret är sant. Genom att sätta ett utropstecken innan kommer vi göra om sant till falskt. Eftersom villkoret nu blir falskt kommer inte echo köras. Om filen istället inte är läsbar för oss kommer villkoret bli falskt, och med ett utropstecken kommer falskt bli sant och echo
kommer köras.
Vi tittar på en mer användbar kodsnutt:
Här använder vi -e
för att titta om filen hemliginfo.dat
finns. Om den inte finns skall skriptet avslutas. Ett mycket bra sätt att felhantera skriptet om vårt skript är beroende av att en fil finns.
Villkor med strängar
I denna del skall vi titta på hur vi kan hantera villkor för strängar.
| Villkor | Förklaring |
| ======= | ========== |
| -z
| Är strängen tom? |
| -n
| Är strängen inte tom? |
| str1 = str2
| Är str1 lika som str2? |
| str1 != str2
| Är str1 inte lika som str2? |
| str1 < str2
| Är str1 mindre än str2? |
| str1 > str2
| Är str1 större än str1? |
Vi börjar med att titta på -z
och -n
:
Skriv ovanstående exempel som ett skript och kör skriptet. ändra sedan så det står STR=""
och kör skriptet igen. Att veta om en variabel är tom innan vi börjar använda den är mycket användbart.
Vi tittar nu på hur vi kan se om två variabler är lika:
Varje tecken vi kan skriva i en dator finns i en teckenkodningstabell som kallas ASCII (American Standard Code for Information Interchange). ASCII är en sju bitarstabell som rymmer de tecken som behövdes i USA, vilket gör att våra svenska tecken som Å, Ä och Ö inte finns med i tabellen. Därför utökades ASCII till olika ISO-standarder som hade åtta bitar för varje tecken. För att skriva västeuropeiska tecken (som å, ä och ö) användes ISO-8859-1 teckenkodning. När valutan euro introducerades i Europa utökades ISO-8859-1 med tecknet för euro och cent. Nu förtiden använder vi teckenkodningstabellen UTF-8 som sägs täcka alla behov av tecken i hela världen.
Tecknet 0
har det numeriska värdet 48 i ASCII-tabellen, tecknet 9
har det numeriska värdet 57. Stora A
har det numeriska värdet 65. Lilla a
har det numeriska värdet 97.
Att titta på om en sträng är större än eller mindre än fungerar inte rikigt som vi tänker oss att det borde fungera. Vad större än och mindre än gör är att jämföra tecknens ASCII-koder (se ovan angående ASCII). Om vi till exempel jämför orden sommar och vår skulle vi kunna tänka oss att sommar skulle vara större än vår, eftersom sommar är längre än vår. Så är inte fallet i Bash, jämförelsen säger att vår är större än sommar, eftersom ASCII-koden för bokstaven v
är 118 och för bokstaven s
är ASCII-koden 115. Villkoret skall alltså tolkas som 118 är större än 115:
Vill vi se vilken sträng som är störst (längst) får vi räkna ut längden på en sträng med #
som i ${#STR1}
. Vi provar:
I exemplet ovanför ser vi att variabeln VAR
innehåller fem (5) tecken (jonas). Vi kan använda detta för att se vilken sträng som är längst.
Eftersom linux är fem tecken och windows är sju tecken långt kommer vi i ovanstående skript få utmatningen linux är kortare än windows. Vi kan göra skriptet kortare med else
:
Om STR1
inte är längre än STR2
kan vi utgå från att STR1
är kortare än STR2
. Notera dock att vi inte tar hänsyn till om strängarna är lika långa i exemplen ovanför.
Matematiska villkor
Vi kan jämföra tal med Bash också.
| Villkor | Förklaring |
| ======= | ========== |
| nr1 -eq nr2
| Är nr1 och nr2 lika (equal)? |
| nr1 -ne nr2
| Är nr1 och nr2 olika (not equal)? |
| nr1 -lt nr2
| Är nr1 mindre än nr2 (less than)? |
| nr1 -le nr2
| Är nr1 mindre än, eller lika med, nr2 (less than or equal)? |
| nr1 -gt nr2
| Är nr1 större än nr2 (greater than)? |
| nr1 -ge nr2
| Är nr1 större än, eller lika med, nr2 (greater than or equal)? |
För att jämföra två variabler med värden kan vi göra så här:
Vi skapar en fil där vi skriver in skriptet ovanför och kör det för att se vad som händer. Sedan ändrar vi TAL1
och TAL2
till andra värden för att kontrollera att det fungerar som det skall.
Flera villkor
Det händer ibland att vi vill kunnna jämföra flera villkor samtidigt. Att en fil finns betyder inte alltid att den går att skriva till. För att kunna använda flera villkor behöver vi använda -a
(för and, och) och -o
(för or, eller). Säg att vårt skript behöver veta om en fil finns och att skriptet kan skriva till filen, om dessa villkor inte uppfylls skall vi avsluta skriptet:
Vad vi säger i vårt villkor (i skriptet ovanför) är om filen datafil.dat
inte finns (! -e ./datafil.dat
) eller (-o
) filen inte är skrivbar (! -w ./datafil.dat
) skall vi skriva ett felmeddelande och avsluta skriptet.
Om inte ett villkor uppfylls, kanske ett annat gör det?
I våra if-satser (villkoren) har vi testat om ett, eller flera (med and och or), villkor är uppfyllda. Hur gör vi om vill testa om ett villkor uppfylls, och göra något annat om villkoret inte är uppfyllt?
I exemplet ovanför testar vi om variabeln $TAL
är större eller lika med 10, om $TAL
är större eller lika med 10 kommer vi skriva ut texten Talet är 10 eller högre om det är mindre än 10 (villkoret uppfylls inte) kommer vi skriva ut texten Talet är mindre än 10 istället.
Här använder vi oss av else
som vi kan läsa som: om villkoret är sant gör vi det här, om det inte är sant (else) gör vi det här.
Det händer att vi vill testa flera villkor på en och samma variabel. Vi tittar på ett exempel där vi skall skriva ett skript som räknar ut betyg för elever. Vi skriver följande:
Variabeln $BETYG
innehåller antalet poäng eleven har skrivit på provet. Gränsen för godkänd har vi satt till 50 poäng och gränsen för väl godkänd har vi satt till 80 poäng. Allt under 50 poäng kommer resultera i betyget icke godkänd.
Vi använder oss av elif
i skriptet ovanför. elif
är en förkortning av else if (annars om). elif
använder vi när vi behöver testa flera olika villkor.
Om vi sätter variabeln $BETYG
till 90 kommer det första villkoret (större än 80) att uppfyllas, dessutom kommer det andra villkoret (90 är större än 50) att uppfyllas. Varför kommer skriptet inte skriva ut både VG och G?
En if-elif sats avbryter hela if-satsen när det första villkoret är sant. Därför kommer vi avsluta hella villkorstestet när villkoret ${BETYG} -ge 80
uppfyllts.
Loopar
Med loopar kan vi upprepa samma sak om och om igen, i all oändlighet eller tills något uppfyller ett villkor. Vi skall titta på tre olika loopar i Bash: while
, for
och until
While
while-loopar används för att skapa loopar som håller på så länge som ett villkor är uppfyllt, eller avbryts med kommandot break
. En while-loop skrivs så här:
Vi testar det i ett skript:
Skriptet kommer köras i all oändlighet, eller tills vi avbryter det genom att trycka CTRL
och D
samtidigt. Om ett villkor inte uppfylls på första försöket kommer kommandona mellan while
och done
aldrig att köras.
För att skapa ett bättre skript bör vi lägga till något sätt att ta oss ur while-loopen, förutom att trycka CTRL+D
. Vi skriver om vårt skript:
Ett villkor kan vara sant eller falskt. Vi kan använda orden true
och false
för att skapa våra villkor:
Vi kan naturligtvis också bestämma hur många gånger något skall upprepas genom att skapa en räknare:
for
En for-loop repeterar något så länge den har något att repetera.
Låt oss säga att vi har ett antal filer som vi vill komprimera med gzip
, en for-loop skulle klara saken enkelt:
I skriptet ovanför kommer vi att komprimera filerna fil1.sh
, fil2.sh
och fil3.sh
med gzip
.
En for-loop kan användas med en räknare också, om vi vill göra något ett bestämt antal gånger:
until
until
använder vi för att skapa loopar som skall upprepas tills ett villkor uppfylls. Ett exempel:
I exemplet ovanför kommer until köras tills användaren matar in namnet jonas.
Vill vi att until-loopen skall köras ett visst antal gånger kan vi skriva som i följande skript:
I exemplet ovanför kommer until
-loopen skriva ut 1, 2 och 3.
Argument
När vi använder kommandon från kommandoraden kan vi ofta skicka med argument till kommandot. När vi vill kopiera en fil kan det se ut så här:
Kommandot cp
(copy) tar emot två argument: filen.txt
som är filen vi vill kopiera och kopian.txt
som är namnet på den kopia vi vill skapa.
Ofta vill vi använda argument till våra egna skript också, så användaren av skriptet kan påverka vad som skall hända, eller göras, i skriptet. I den här delen tittar vi på hur det fungerar i Bash.
I Bash finns det ett par fördefinerade variabler som hanterar argument:
$#
innehåller hur många argument vi har skickat till skriptet.$0
innehåller skriptets namn (filnamnet).$1
innehåller det första argumentet.$2
innehåller det andra argumentet.$3
,$4
,$5
och så vidare innehåller det tredje, fjärde och femte argumentet som skickats till skriptet.$*
innehåller alla argument.
Om vi nu går tillbaka och tittar på kopieringen av filen i exemplet ovanför:
Här skulle $#
säga 2, eftersom vi har två argument. $0
skulle vara cp, eftersom det är skriptets namn. $1
skulle innehålla filen.txt och $2
skulle innehålla kopian.txt.
Nu skriver vi ett skript som använder sig av argument:
Vi sparar skiptet och kör det:
Det är lämpligt att deklarera en variabel som fångar upp argumentet i skriptet, så vi inte får problem med till exempel $1
senare i skriptet:
Om ett skript vi skapar behöver argument för att fungera bör vi också ha en kontroll om det kommer ett argument till skriptet. För att kontrollera om vi får in argument till ett skript kan vi skriva så här:
I skriptet ovanför kontrollerar vi om vi har ett ($# -ne 1
) argument skickat till oss. Om vi inte har ett argument skall vi skriva ut ett felmeddelande, här använder vi $0
för att skriva ut skriptets namn innan meddelandet. Efter felmeddelandet avslutar vi skiptet med exitkoden 1.
Om vi istället vill ha minst ett, eller fler argument skriver vi [ $# -ge 1 ]
i skripet. Då kommer vi kontrollera om vi har ett, eller flera, agument skickade till skriptet.
Med variabeln $*
får vi fram alla argument som skickades till skriptet, till exempel så här:
Vi sparar skiptet med filnamnet argument.sh
och kör det:
Vill vi använda argumenten till något användbart kan vi till exempel använda en for-loop:
När vi kör skriptet kommer det se ut så här:
Slumpade tal
Slumpade tal är användbara när vi vill att slumpen skall ha en avgörande roll i våra skript, till exempel slå en tärning. Bash har en variabel som ger oss slumpade tal mellan 0 och 32767: $RANDOM
.
Om vi vill ha ett slumpat tal mellan 0 och 100 låter vi $RANDOM
slumpa ett tal och sedan använder vi modulus för att få resten vid en division:
För att få ett tal mellan 1 och 100 skriver vi:
Först tar vi ett slumpat tal med $RANDOM
, sedan kör vi det genom modulus 100 vilket ger oss ett tal mellan 0 och 99. Eftersom vi ville ha ett tal mellan 1 och 100 adderar vi 1 till talet vi slumpat fram.
En tärning där vi vill ha ett värde mellan 1 och 6 slumpar vi fram enligt:
Om vi vill ha ett slumpat tal mellan 20 och 40 börjar vi med att använda modulus 21 (vilket ger oss tal mellan 0 och 20, 21 olika värden) och sedan adderar vi 20:
Vi måste alltså hålla koll på vad vår offset är (20) och hur många värden från det vi vill nå (21). Om vi vill ha ett slumpat tal mellan 50 och 80 är det 31 som är hur långt vi vill (80 - 50) nå och vår offset är 50 (där vi skall börja):
Köra program och fånga upp dem från skriptet
Vi kan köra program och jämföra deras utmatning mot något villkor i en if-sats eller tilldela en variabel värdet av vad kommandot matar ut. Detta gör vi genom att skriva kommandot inom $( )
, till exempel $(ls)
eller $(ls -l)
.
För att kontrollera om användaren är inloggad som root kan vi skriva så här i vårt skript:
Ett bättre sätt att kontrollera om skriptet körs som användaren root är [ $EUID -ne 0 ]
. Där $EUID
innehåller användar-id för den användare som kör skriptet. Användaren root har användar-id noll (0).
Vi kan tilldela en variabel värdet av vad ett program returnerar:
Alla program som körs i systemet returnerar en exit code, precis som vi har gjort med våra skript: exit 0
. Noll (0) är standard för att visa att allt gick bra, programmet lyckades utan fel. Exit värden mellan 1 och 255 är felkoder som har olika betydelser. Vanligast är att 1 betyder fel, men många program har olika värden beroende på vilket fel som uppstod. På så sätt har vi lättare att fånga upp fel i våra skript. Vi tittar på det från kommandoraden:
Eftersom vi har rättigheter att skapa filer i katalogen /tmp
kommer det första kommandot lyckas. I katalogen /proc
däremot har vi inga skrivrättigheter och kommandot touch
misslyckas, vi får tillbaka en etta (1) som indikerar ett fel.
Vi får också ett felmeddelande som inte är så fint att ha med i ett skript, vi skulle kunna dirigera om STDERR
till /dev/null
för att dölja felmeddelandet:
/dev/null
är en speciell fil som ofta används för att kasta bort utskrifter från skript. Allt vi dirigerar om till /dev/null
försvinner, som i ett svart hål. Om vi läser /dev/null
får vi enbart tillbaka specialtecknet end of file (EOF).
Om vi vill använda exitvärdena i våra skript kan vi till exempel skriva:
Funktioner
Funktioner använder vi för att återanvända kod. Tänk dig att vi vill göra samma sak flera gånger i ett skript, men på olika ställen i skriptet. Varför skriva om samma kod om och om igen då?
Funktioner skrivs så här:
En enkel funktion i ett skript kan skrivas så här:
När vi kör ovanstående skript kommer vi anropa funktionen funk
som kommer skriva ut Hej från funktionen funk på skärmen.
Variabler som skapas i skriptet är som standard globala, det vill säga: de är tillgängliga överallt i skriptet. Vi kan alltså använda variabler i våra funktioner, som i det här skriptet:
I skriptet ovanför kommer vi be användaren att mata in sitt namn, som vi lagrar i variabeln $NAMN
. Sedan anropar vi funktionen ditt_namn
som kommer använda variabeln $NAMN
för att skriva ut det inmatade namnet.
Variabler vi skapar i funktionen kommer också att vara globala, vårt skript kommer alltså åt dem och kan använda dem. Detta hindrar vi med kommandot local
som skapar en lokal variabel i funktionen. Den lokala variabeln är inte tillgänglig utanför funktionen. Vi tittar på ett exempel:
I exemplet ovanför kommer vi att anropa funktionen lokalvar
som deklarerar en lokal variabel, $MAGISK
, som vi sedan skriver ut på raden under med echo
. Efter all kod i funktionen körts hoppar skriptet tillbaka till raden under funktionsanropet (lokalvar
i skriptet) och skriver ut $MAGISK
igen med echo
. Den här gången är $MAGISK
tom, eftersom vi inte har deklarerat variabeln och $MAGISK
i funktionen lokalvar
är en lokal variabel för just den funktionen.
Vi har tidigare tittat på hur vi kan skicka in argument till skript, detta fungerar för funktioner också. $#
innehåller hur många argument som skickas, $1
innehåller det första argumentet och så vidare.
Vi börjar med att skapa ett skript med funktionen summa
som adderar två tal och skriver ut summan:
Först anropar vi funktionen summa
med två tal: summa 10 20
och funktionen skriver ut summan av de två talen. Därefter ber skriptet användaren om två tal. När användaren har matat in dem anropas funktionen summa
med de två inmatade talen.
Returvärden
Funktioner kan returnera värden, precis som våra skript kan returnera värden med exit
. Funktionerna använder sig av return
istället och kan returnera ett värde mellan 0 och 255. Returvärdet fångar vi upp med variabeln $?
.
I skriptet ovanför skickar vi in talen 10 och 30 till funktionen summa som räknar ut summan av talen och lagrar svaret i variabeln $SUMMA
. Sedan returnerar vi noll med return 0
.
Vi fångar upp returvärdet med variabeln $?
på raden under anropet till funktionen och variablen $SUMMA
på nästa rad.
Tänk på att returvärden bara kan returnera heltal mellan 0 och 255. För att fånga upp resultat av beräkningar och liknande i funktioner får vi jobba med variabler (som $SUMMA
) i exemplet ovanför.
Source
Ibland vill vi inkludera ett annat skript i det skript vi kör just nu. Det kan till exempel vara ett skript med funktioner och konfigurering som vi vill använda i flera andra skript. I Bash använder vi source
för att inkludera andra skript i det skript vi kör.
När vi använder source
läser vårt skript in det andra skriptet och kör det direkt. Vi tittar på ett exempel.
Vi börjar med att skapa skriptet source2.sh
:
Vi fortsätter med att skapa skriptet source1.sh
:
Nu kör vi skriptet source1.sh
och ser vad som händer:
Om vi vill använda oss av variabler mellan skripten ser det ut så här. Vi ändrar source2.sh
till:
Sedan ändrar vi source1.sh
till:
Nu kör vi source1.sh
och ser vad som händer:
Vi skapar alltså en variabel ($NAMN
) i skriptet source1.sh
som sedan används i skriptet source2.sh
.
source
kan också förkortas som en punkt (.
) som i . skript2.sh
. Notera mellanslaget mellan punkten och skriptets namn.
Logghantering och felsökning
Loggfiler är till stor hjälp när vi felsöker ett linuxsystem. Linuxkärnan, tjänster som körs i systemet och många applikationer skriver loggfiler. Det finns flera loggfiler i systemet, syslog (systemloggen) är bland de viktigaste att känna till. Loggfilerna lagras i katalogen /var/log/
och där hittar vi ett par loggfiler.
/var/log/auth.log
-
innehåller information om anslutningar och inloggningar (och inloggningsförsök).
/var/log/dmesg
-
innehåller meddelanden från linuxkärnan, vi kan visa loggfilen med kommandot
dmesg
/var/log/lastlog
-
innehåller information om vilka användare vi har på systemet och när de senast loggade in (och varifrån). Loggfilen är inte i textformat utan en databas, vi måste använda kommandot
lastlog
för att visa loggen. /var/log/syslog
-
är sysloggen (på en del linuxsystem heter loggfilen
/var/log/messages
). Numera hamnar det mesta i journald-loggen.
Vi hittar också ett par kataloger i /var/log/
. Katalogerna är för specifika tjänster i systemet. apt
innehåller loggar från apt-kommandot. Installerar vi webbservern Apache på systemet kommer den logga till katalogen /var/log/apache2/
.
Det är en tjänst som heter rsyslogd
som hanterar loggfiler i Linux. rsyslogd
har en konfigurationsfil som heter /etc/rsyslog.conf
, den har också en katalog som heter /etc/rsyslog.d/
där vi kan lägga egen konfiguration till rsyslogd.
rsyslogd kan logga lokalt till systemets disk, eller till en rsyslogd-server över nätverk. Nätverkskommunikationen sker över port 514 med UDP- eller TCP-protokollet. Vi kan också logga både till en nätverksserver och den lokala disken samtidigt.
Scenario: vi får intrång i vår server och någon illasinnad hacker installerar en Bitcoin-miner. För att radera alla spår från intrånget raderar hackern allt i loggfilerna på disken som kan avslöja henne. Om vi hade loggat allt till en nätverksserver hade vi haft spåren kvar i loggfilerna på den servern. |
rsyslogd har också ett system för att vi skall kunna fånga upp loggmeddelanden och skicka dem till rätt ställe: facilities och levels:
- facilities
-
auth, authpriv, cron, daemon, ftp, kern, lpr, mail, news, syslog, user, uucp, local0, local1, local2, local3, local4, local5, local6, local7
- levels
-
emerg, alert, crit, err, warning, notice, info, debug
Hur rsyslogd loggar de olika meddelandena specifierar vi i konfigurationen för rsyslogd: /etc/rsyslog.d/50-default.conf
:
Raderna ovanför visar några exempel på vilka regler vi har i /etc/rsyslog.d/50-default.conf
.
Om vi börjar med raden som ser ut så här: *.*;auth,authpriv.none -/var/log/syslog
. Här är den första matchningen *.*
, vilket betyder att alla facilities med alla levels skall loggas till /var/log/syslog
. Vi provar att skapa ett meddelande med kommandot logger
:
Nu kan vi titta i /var/log/syslog
om det kom in i loggfilen, vi kan till exempel använda kommandot grep
för att söka efter strängar (tecken) i filen:
Vi har en regel som säger cron.* /var/log/cron
, allt som går till facility cron
oavsett level skall hamna i filen /var/log/cron
. För att prova denna måste vi avkommentera raden (ta bort #-tecknet) i filen /etc/rsyslog.d/50-default.conf
:
#
-tecknet betyder att raden är en kommentar och skall ignoreras, det vill vi inte - så vi tar bort tecknet.
Nu startar vi om tjänsten rsyslog
för att läsa in konfigurationen:
För att skicka ett meddelande till facility cron kan vi använda kommandot logger
igen:
Nu skapades filen /var/log/cron.log
(om den inte redan fanns) och där kom meddelandet vi skickade med kommandot logger
.
Så med kommandot logger
kan vi ange facility.level med -p
. Om vi inte anger något kommer user.notice
att användas som standard. Vi kan också tagga våra meddelanden, vilket kan vara bra om vi enkelt vill kunna söka efter dem. Då använder vi flaggan -t
så här:
Nu är det enkelt att hitta alla meddelanden som är taggade med JONAS med hjälp av kommandot grep
:
Taggning av meddelanden är användbart när vi skriver egna skript och enkelt vill kunna hitta meddelanden från skripten. Ett skript är en serie kommandon som skrivs in i en fil, för att sedan köras tillsammans. |
Loggrotatation
Eftersom det skrivs i loggfilerna hela tiden kommer de bli stora och ta mycket plats på disken. Därför använder vi något som kallas logrotate
. Logrotate har sin konfigurationsfil i /etc/logrotate.conf
och katalogen /etc/logrotate.d/
. I konfigurationen ställer vi in hur olika loggfiler skall hanteras av logrotate. Logrotate tar loggfilen och roterar den vilket innebär att den nuvarande loggfilen kan komprimeras och sparas undan i ett komprimerat format. Ofta döps roterade loggfiler till namnet och sedan filändelsen .1
, .2
och så vidare. Komprimerar vi loggfilen kommer filnamnet sluta med .gz
.
Logrotate körs varje dag med hjälp av schemaläggaren cron
, jobbet för logrotate ligger i filen /etc/cron.daily/logrotate
. För loggfilen /var/log/syslog
ser logrotatejobbet ut så här:
rotate
anger hur många gånger en fil skall roteras innan den skall raderas. Här sparar vi de senaste 7 filerna.daily
anger att vi skall rotera filerna varje dagmissingok
om loggfilen saknas ignorerar logrotate den, vi får alltså inget felmeddelande. Motsatsen ärnomissingok
.notifempty
anger att vi inte skall rotera filen om den är tom.delaycompress
anger att vi skall komprimera den roterade loggfilen vid nästa tillfälle logrotate körs.compress
anger att vi skall komprimera (medgzip
) loggfilerna som roteras.postrotate
börjar ett block med kommandon som slutar medendscript
. De kommandon som står mellan postrotate och endscript kommer köras med kommandotolken/bin/sh
när logrotate körs.
lastlog
Med kommandot lastlog
kan vi se när användare senast loggade in på systemet. När vi kör lastlog
visas alla användarkonton vi har i systemet. Vill vi bara se när en specifik användare loggade in senast använder vi -u användarnamn
till kommandot. Så här för användaren root:
journald
Ubuntu använder uppstarts- och tjänstehanteraren systemd
som kommer med logghanteraren journald
. Med kommandot journalctl
kan vi hämta information från alla loggar i systemet på ett enklare sätt, men detta fungerar bara med de linuxdistributioner som använder systemd. De flesta nya linuxdistributioner använder systemd, eftersom man vill standardisera på systemd. Saknar vi kommandot journalctl
på datorn betyder det att vi får läsa loggfilerna manuellt, som vi gick igenom innan.
Det allra enklaste sättet att läsa loggarna med journalctl
är att bara skriva kommandot och köra programmet:
Loggarna visas och vi hoppar upp och ned med hjälp av Page Up/Page Down. Vi avslutar listningen genom att trycka på tangenten q
.
Vill vi visa boot-loggen, det vill säga allt som loggats medan systemet startade upp skriver vi:
För att enbart visa meddelanden från linuxkärnan skriver vi:
Vi kan visa meddelanden som är taggade med något specifikt genom att skriva:
Här kommer vi få alla meddelanden som är taggade med jonas (se exemplet med kommandot logger
tidigare i det här dokumentet).
I systemd finns något som kallas units, vi kommer till det senare i kursen när vi skall prata om systemd och tjänster. Journalctl kan visa meddelanden från units genom att skriva till exempel (för cron):
Med -p
kan vi filtrera på vilken prioritet ett meddelande har, för att till exempel se alla felmeddelanden (err) i loggarna skriver vi:
Det finns åtta olika nivåer av prioritet: emerg, alert, crit, err, warning, notice, info och debug. |
För att följa en logg, det vill säga visa alla nya meddelanden som kommer in i loggen använder vi -f
:
Vi avbryter genom att hålla nere tangenten CTRL och trycka på c
samtidigt.
Vi kan välja från vilket datum och tid och till vilket datum och tid vi vill visa loggmeddelanden. Tiden anger vi i formatet "2016-09-01 07:00:00"
, om vi inte anger tiden utan bara datum "2016-09-01"
kommer tiden 00:00:00
användas. Vi kan också ange tiden som yesterday
, today
, tomorrow
och now
. Vi använder flaggorna --since=
och --until=
för att filtrera på tid, till exempel:
Det första kommandot kommer visa alla loggmeddelanden från 2016-08-01 00:00:00 till 2016-08-02 00:00:00. Det andra kommandot kommer visa alla loggmeddelanden från 2016-08-01 00:00:00 till nu.
Vi kan hämta loggar från specifika program och tjänster som körs i systemet. Vi har till exempel en SSH-server igång som standard i Ubuntu. Den tjänsten körs av programmet /usr/sbin/sshd
och för att visa loggfilerna från tjänsten skriver vi:
Vi kan också kombinera många av valen till journalctl, till exempel om vi bara vill visa felmeddelanden från tjänsten cron skriver vi:
Systemd
I den här delen kommer vi:
- Gå igenom vad systemd är
- Lära oss att hantera tjänster i Linux
Systemd är en system- och tjänstehanterare för Linux. Det har funnits några sådana genom tiderna, varav SysV init var den allra vanligaste uppstartshanteraren, sedan kom Upstart och nu är det Systemd som gäller för de flesta större linuxdistributioner. Med systemd hanterar vi hur systemet skall starta upp (boota) och vi kan hantera de tjänster som vi har installerade: vi kan starta dem, stänga ner dem, starta om dem och så vidare.
Med systemd kan vi starta tjänster parallelt, vilket innebär att uppstarten av en linuxmaskin blir mycket snabbare. Systemd tar reda på vilka tjänster en specifik tjänst är beroende av och startar dem sedan i turordning. Systemd är också bakåtkompatibel, vilket innebär att vi kan använda skript för SysV init och Upstart tjänsterna.
Systemd använder sig av något som kallas units, en unit är en konfiguration av en specifik tjänst. Tjänste-units i systemd kallas namn.service
och kan användas för att till exempel starta, stänga ner, starta om, aktivera och inaktivera tjänsten. Vi använder kommandot systemctl
för att hantera tjänsterna:
systemctl start name.service
-
Startar tjänsten
name
systemctl stop name.service
-
Stänger ner (avslutar) tjänsten
name
systemctl restart name.service
-
Startar om tjänsten
name
systemctl try-restart name.service
-
Startar bara om tjänsten
name
om den redan körs. systemctl reload name.service
-
Läser in konfigurationen för tjänsten
name
igen. Bra när vi konfigurerat om en tjänst och vill läsa in den nya konfigurationen. systemctl status name.service
-
Visar status för tjänsten
name
systemctl is-active name.service
-
Visar om tjänsten
name
körs. Ungefär somstatus
men med enklare utmatning. systemctl list-units --type service --all
-
Visar status för alla tjänster i systemet.
Systemd hanterar uppstarten av linuxsystemet och bestämmer vilka tjänster som skall starta upp vid uppstart (boot) och vilka som inte skall starta upp. Vi hanterar detta med enable
och disable
i systemd.
systemctl enable name.service
-
Aktiverar tjänsten
name
systemctl disable name.service
-
Inaktiverar tjänsten
name
systemctl is-enabled name.service
-
Visar om tjänsten
name
är aktiverad eller inte.
Om vi inte skriver .service
efter en tjänsts namn kommer systemd förutsätta att vi menar just .service
. Om vi inte angett något annat så klart. Följande kommandon gör samma sak:
Vi visar alla installerade tjänster som körs genom att skriva:
Listan pausas skärm för skärm och vi använder PAGE-UP och PAGE-DOWN för att förflytta oss. Vi avslutar listningen genom att trycka på tangenten q
.
För att visa alla tjänster och deras status (även de som inte körs) skriver vi:
Vi kan också visa status på alla tjänster med list-unit-files
:
Om vi vill visa status för en specifik tjänst använder vi status
:
- Loaded
-
informerar om tjänsten är laddad, vilken sökväg den finns på och om den är aktiverad (enabled).
- Active
-
visar om tjänsten körs just nu, och i så fall när den startades.
- Main PID
-
visar vilket process id (PID) som startade tjänsten.
- CGroup
-
visar information om de CGroups (control groups) som är relaterade till tjänsten.
Om vi bara vill se om tjänsten är startad eller inte använder vi is-active
:
Vill vi veta om en tjänst aktiveras vid uppstart använder vi enabled
:
För att starta en tjänst använder vi start
:
För att stänga ner en tjänst använder vi stop
:
I exemplet kommer vi stänga ner SSH-tjänsten på vår maskin. Gör inte detta om du använder SSH för att ansluta till din linuxmaskin! |
Ibland behöver vi starta om en tjänst, kanske för att vi konfigurerat om den eller att den slutat svara. Då använder vi restart
:
Vi kan också använda try-restart
som bara startar om tjänsten om den redan körs. Detta gör att vi inte startar upp tjänster som inte redan var igång.
En del tjänster klarar av att läsa om sin konfiguration utan att starta om hela tjänsten med restart
. Då använder vi reload
istället:
Om vi vill att en tjänst skall starta upp när systemet startar använder vi enable
:
För att se till att tjänsten inte startar upp med systemet använder vi disable
:
Targets
Om du har använt Linux tidigare kanske du känner till runlevels. I SysV init var de numrerade 0 till 6. Där man valde vilken runlevel man ville att systemet skulle köras i. Vanligtvis var det runlevel 2 eller 3 för en server utan grafisk miljö och 5 för en server med grafisk miljö. I systemd heter de olika runlevels targets och vi har fortfarande sju stycken (0-6):
- runlevel0.target, poweroff.target
-
stänger ner systemet och datorn (stänger av strömmen)
- runlevel1.target, rescue.target
-
startar ett räddningsläge där vi kan laga ett trasigt linuxsystem
- runlevel2.target, multi-user.target
-
startar en fleranvändarmiljö utan grafik
- runlevel3.target, multi-user.target
-
startar en fleranvändarmiljö utan grafik
- runlevel4.target, multi-user.target
-
startar en fleranvändarmiljö utan grafik
- runlevel5.target, graphical.target
-
startar en fleranvändarmiljö med grafik
- runlevel6.target, reboot.target
-
stänger ner systemet och startar om datorn
För att se vilka targets vi har laddade nu skriver vi:
För att se alla tillgängliga targets lägger vi till --all
:
För att se vilken target som är standard använder vi get-default
:
För att ändra target använder vi isolate
, för att starta om datorn skriver vi:
För att ändra vilken target systemet skall starta upp i använder vi set-default
:
För att återställa till den target vi använder när vi kör textbaserat läge skriver vi:
Stänga ner och starta om Linux
systemctl halt
-
stänger ner systemet, men behåller strömmen
systemctl poweroff
-
stänger ner systemet och stänger av strömmen
systemctl reboot
-
startar om systemet
Nätverk
En av de viktigaste funktionerna för vår server är nätverket. Det dominerande protokollet för nätverk idag är TCP/IP. TCP/IP är egentligen två protokoll, ett för transporten av datapaket (TCP) och ett för adresseringen av nätverk och noder i nätverk (IP). Det är den här protokollstacken vi använder hemma, i skolan och på företaget. När vi surfar på webben använder vi protokollet Hyper Text Transfer Protocol (HTTP) och ibland är det HTTPS. HTTPS är HTTP som skickas över en krypterad förbindelse, tidigare SSL - numera TLS. När vi skickar epost använder vi oss av ett protokoll som heter Simple Mail Transfer Protocol (SMTP) och när vi hämtar epost använder vi oss av POP3- eller IMAP-protokollen. Även om tjänster som GMail och Outlook.com har tagit över mycket av epostandet idag är det fortfarande SMTP och POP3/IMAP som ligger där och arbetar bakom webbsidorna.
Under alla dessa protokoll (det finns många fler) skickar vi våra datapaket över kablar, radiovågor och ljus (fiber). Den standard som är vanligast förekommande för överföring av datapaket heter Ethernet. Ethernet delas upp i olika standarder (eller versioner om man så vill), där IEEE 802.3 är Ethernet över partvinnad kopparkabel (TP-kabel) och IEEE 802.11 som är Ethernet över radiovågor (WiFi). Dessa standarder delas också in i undergrupper, där vi kan hitta 10 megabit Ethernet, 100 megabit Ethernet, 1000 megabit Ethernet och 10 000 megabit Ethernet under 802.3. Hastigheten är inte allt, undergrupperna definerar också om det är koppartråd, koaxialkabel eller fiber vi använder och hur lång kabeln får vara. Under den trådlösa standarden 802.11 hittar vi undergrupper som 802.11b, 802.11g, 802.11n och 802.11a.
Det finns andra typer av nätverk också, som Token Ring, FDDI och ATM. Här kommer vi bara gå igenom Ethernet, eftersom det är det vanligast förekommande.
TCP/IP
För att en enhet (dator) skall kunna kommunicera i ett TCP/IP-nätverk behöver den ha minst två saker konfigurerade: en unik IP-adress och en nätmask. Nätmasken används av enheten för att identifiera vilket nätverk enheten finns på. IP-adressen och nätmasken tillsammans berättar vilken enhet (host) och vilket nätverk (net) enheten befinner sig på.
Vi brukar konfigurera två saker till när vi konfigurerar TCP/IP för en enhet: en default gateway och DNS-server. Default gateway använder vi för att berätta för enheten hur den skall komma ut ur sitt egna nätverk, till exempel när vi vill titta på kattfilmer på Youtube, eller titta på Facebook, så vi vet vad vår kompis åt till lunch idag. DNS-servrar använder vi för att göra om domännamn som youtube.com och facebook.com till IP-adresser som 142.250.74.110 och 31.13.72.36 .
De fyra saker vi behöver för att ha en fungerande enhet på ett TCP/IP-baserat nätverk är:
- IP-adress
- Nätmask
- Default Gateway
- DNS-server (eller flera)
För att se vilken IP-adress och nätmask vi har konfigurerat på vår
dator använder vi kommandot ip address
(eller ip addr
eller ip a
som är förkortningar av kommandot).
Här ovanför ser vi att vi har två nätverksgränssnitt (network interface): lo
och eth0
. Gränssnittet lo
är speciellt och heter local loopback. Det har alltid IP-adressen 127.0.0.1 och IPv6-adressen ::1. Det är ett gränssnitt som bara går att komma åt från vår egen dator, alltså inte utifrån.
Det andra gränssnittet, eth0
, är vårt nätverkskort som sitter i datorn. Vi kan ha flera sådana och då visas de också med kommandot ip address
. I det här exemplet har vårt nätverkskort IP-adressen 10.0.1.196 och nätmasken /24. Adressen skrivs enligt en standard som kallas Classless Inter-Domain Routing (CIDR) (uttalas cider) och anger hur många bitar av IP-adressen som är nätverksidentiteten. I det här exemplet är det 24 bitar som används för att identifiera nätverket enheten befinner sig i.
Vi har också en link/ether
adress, i exemplet: 04:92:26:d4:b1:63
. Det är en adress som kallas MAC-adress. Varje nätverkskort som tillverkas får en egen, 48 bitar lång, adress som används för att kommunicera med nätverkskortet.
För att se vilken default gateway vi använder skriver vi kommandot ip route
(eller bara ip r
):
Här ser vi att default går via IP-adressen 10.0.1.1 . Det betyder att all nätverkstrafik som skall ut ur vårt egna IP-nätverk till, till exempel internet, skall skickas till IP-adressen 10.0.1.1 . Där finns förhoppningsvis en nätverksenhet som kallas router. Routern skickar trafiken vidare till nästa nätverk, som skickar till nästa nätverk och så vidare tills vi har nått vårat mål (till exempel Youtube.com). Målet skickar tillbaka ett svar som skickas till en router, som skickar till nästa router, och så vidare tills vi når målet (vår dator).
Vår default gateway (router) måste vara i samma nätverk som vår enhet är. Det vill säga, inom samma IP-adress- område. Syftet med en default gateway är att skicka ut (och in) trafik till andra nätverk. Vi måste alltså ha den i samma nätverk.
Datorer kommunicerar med andra enheter med hjälp av IP-adresserna, men vi använder domännamn som facebook.com och youtube.com. För att datorerna skall kunna göra om facebook.com till en IP-adress frågar de en DNS-server. Det fungerar lite som nummerupplysningen på internet. Vi kan fråga vilket telefonnummer Jonas har, och så får vi veta det. Känner vi till ett telefonnummer kan vi också använda tjänster på internet för att ta reda på vem det numret går till. DNS fungerar likadant, fast för IP-adresser.
Vi kan använda kommandot dig
för att ta reda på vilken IP-adress till exempel facebook.com har:
Här ovanför ser vi att facebook.com går till IP-adressen 157.240.9.35 . Låt oss titta på aftonbladet.se också, vi gör samma sak med kommandot dig
:
I exemplet ovanför ser vi att vi får två IP-adresser som svar. Det innebär att vår webbläsare kommer använda en av dem för att ansluta till aftonbladet.se om vi vill titta på deras nyheter. Att det är två (eller flera) IP-adresser konfigurerade för en domän heter DNS Round Robin och är en enklare form av lastbalansering.
Vi kan också använda kommandot host
för att fråga våra DNS-servrar:
Här får vi också veta IPv6-adressen till facebook.com och vilken server som hanterar deras inkommande epost. Denna information finns i en posttyp (record) som heter MX (Mail eXchange) och används varje gång vi vill skicka epost till någon.
Nu gör vi samma sak för aftonbladet.se :
Här ser vi att Aftonbladet använder Google för sin epost (GMail).
Varje gång vi använder kommandot dig
, host
eller något annat kommando som pratar DNS frågar vår dator den DNS-server som vi konfigurerat. I Linux är det filen /etc/resolv.conf
som innehåller informationen om vilka DNS-servrar vi vill använda:
Valet nameserver
anger vilken DNS-server vi vill fråga. Här skall vi alltid ange en IP-adress! I Ubuntu används systemd-resolved
som DNS-server. Det är en tjänst som hanterar namnuppslag (frågor till DNS-servrar) och vi använder kommandot resolvectl
för att hantera tjänsten.
Sist i utmatningen kan vi se de fyra DNS-servrar systemet är konfigurerat att använda:
- 4.2.2.1
- 4.2.2.2
- 208.67.220.220
- 192.168.122.1
Vill vi bara veta vilka DNS-servrar som används skriver vi:
Vi kan använda kommandot resolvectl
för att fråga DNS-servrarna:
För att ställa in så att servern frågar Googles DNS-server skriver vi följande kommando:
För att göra ändringarna permanenta (så det är inställt vid varje omstart) behöver vi redigera filen /etc/systemd/resolved.conf
:
I filen skriver vi:
Efter att vi ändrat i filen och sparat den laddar vi om systemd-resolved
:
IP-adress, nätmask och default gateway brukar vi konfigurera tillsammans. I Ubuntu görs det med hjälp av netplan
. Till att börja med så finns det två olika sätt att konfigurera IP-adressen med: dynamisk- (DHCP) och statisk konfiguration. Hemma brukar vi använda dynamisk konfiguration (DHCP), då det är smidigast. Vi ansluter vår laptop eller mobiltelefon, ansluter den till wifi med ett lösenord och sedan kommer vi ut på internet. Enheten fick IP-adress, nätmask, default gateway och DNS-servrar från nätverket helt automatiskt.
När vi konfigurerar servrar vill vi oftast att de skall ha samma IP-adress hela tiden och för att säkerställa det använder vi statisk konfiguration.
Tänk på att vara försiktig med att ändra IP-adress, nätmask och default gateway på en server som du ansluter till över internet. Konfigurerar du den fel kommer du inte komma åt den. |
Netplan konfigureras i katalogen /etc/netplan/
där vi hittar filen 01-netcfg.yaml
. För att ställa in vårt nätverkskort att använda dynamisk konfiguration redigerar vi filen med texteditorn vi:
Filen är skriven i ett format som kallas YAML. Det är ett vanligt format för konfigurationsfiler för moderna applikationer. Viktigt att tänka på när det gäller YAML är att man använder indrag (indentering) för att skapa avsnitt i konfigurationen. De här indragen skall skapas med mellanslag (två mellanslag) och inte tabbtangenten! Det är också viktigt att filen följer formatteringen, annars kommer det bli fel när vi skall aktivera ändringarna. Var nogrann!
eth0
är namnet på nätverkskortet vi vill konfigurera, vi kan använda kommandot ip address
för att ta reda på namnet på nätverkskortet. dhcp4: true
anger att vi vill använda DHCP (dynamisk konfiguration) och nameservers är en lista med IP-adresser till DNS-servrar vi vill använda. Det här behöver vi inte ange, eftersom vårt nätverk kommer tillhandahålla information om vilka DNS-servrar vi skall använda. I exemplet ovanför visar vi hur vi sätter Googles DNS-servrar för nätverkskortet.
När vi är klara med ändringarna i filen 01-netcfg.yaml
skall vi aktivera den nya konfigurationen, det gör vi med kommandot netplan apply
:
För att ställa in en statisk IP-adress behöver vi ändra i filen 01-netcfg.yaml
igen, men först behöver vi veta vilken IP-adress, nätmask, default gateway och DNS-server vi vill använda. I exemplet nedanför kommer vi använda:
- IP-adress: 192.168.1.100
- Nätmask: /24
- Default gateway: 192.168.1.1
- DNS-server: 8.8.8.8 och 8.8.4.4 (Googles DNS-servrar)
Då öppnar vi filen och redigerar den enligt nedanstående:
När vi är klara med ändringarna aktiverar vi dem med kommandot netplan apply
:
Nu kan vi konfigurera TCP/IP på vår server. Vi kan ändra IP-adress, nätmask, default gateway och DNS-servrar.
Brandväggen
I linuxkärnan finns en inbyggd brandvägg som heter Netfilter. Vi kan hantera Netfilter med ett kommando som heter iptables
. Netfilter jobbar med tre huvudflöden: INPUT
för paket som kommer in till vår dator, OUTPUT
för paket som lämnar vår dator och skall ut på nätverket och FORWARD
som är paket som kommer in till vår dator och sedan skickas vidare ut (routing).
För att se vilka regler vi har aktiverade i brandväggen kan vi skriva iptables -L
:
Vill vi se reglerna för en specifik kedja anger vi helt enkelt dess namn till kommandot också, till exempel för INPUT:
Vi kan också välja FORWARD eller OUTPUT.
När vi tittar på utmatningen från kommandot iptables -L
står det (policy ACCEPT
) , det betyder att policyn är satt till ACCEPT vilket innebär att om ingen regel matchar paketet som kommer så gäller policyn. ACCEPT innebär att paketet kommer accepteras. Policyn kan sättas till antagligen ACCEPT
eller DROP
, vilket innebär att paketet blockeras.
Om vi sätter regler som blockerar inkommande nätverkstrafik på en server som vi bara når över internet måste vi tänka till. Om vi stänger av inkommande trafik till ssh (port 22) kommer vi inte kunna logga in på servern längre.
För att sätta policy på en kedja använder vi kommandot iptables -P
:
När vi jobbar med brandväggsregler i Netfilter måste vi ha kunskap om nätverksprotokoll och portar. Med Netfilter kan vi bygga mycket avancerade nätverksregler där vi i den enklaste formen kan blockera, eller acceptera, nätverkstrafik och i mer avancerade konfigurationer hålla koll på hur många anslutningar en klient gör mot vår server, logga misstänkta anslutningar med mera.
En bra första konfiguration att aktivera på en server som står mot internet med en publik IP-adress, vilket innebär att den är nåbar för alla, är att begränsa åtkomsten till SSH. Så det bara är vi själva som kommer åt den. Ett stort problem med detta blir att vi behöver ha en IP-adress som inte ändrar sig på vår klient, eftersom vi kommer tillåta en specifik IP-adress att ansluta till SSH-tjänsten.
-s 212.213.214.215/32
anger vilken source regeln gäller för. All trafik som kommer från den här IP-adressen kommer träffa regeln om -p tcp
protokollet är TCP och --dport 22
destinationsporten är 22. Det är tjänsten SSH som lyssnar på port 22/tcp och trafik från IP-adressen 212.213.214.215 som skall till SSH på vår server matchar regeln. När vi får en match kommer vi antagligen acceptera inkommande trafik (ACCEPT
) eller neka den (DROP
). I det här fallet, -j ACCEPT
, accepterar vi trafiken. Vi tillåter IP-adressen att ansluta till SSH-tjänsten.
Nästa regel vi behöver sätta är policyn för inkommande trafik. Som det är nu tillåter vi all trafik (policy ACCEPT
):
För att sätta policyn till DROP
(neka all trafik) skriver vi:
Det här innebär att våra regler ser ut så här:
Policyn är satt till DROP, vilket innebär att om vi inte hittar en matchande regel kommer vi neka trafik in till servern. Vi har en regel, den för IP-adressen 212.213.214.215 som tillåter trafik till SSH. Det här betyder att om vi kommer från den IP-adressen och försöker ansluta till SSH-tjänsten så kommer vi tillåtas ansluta, medan all annan inkommande trafik kommer nekas.
Om vi gör en anslutning från servern ut mot internet, eller en annan maskin i vårt nätverk, kommer svaret att komma in genom brandväggen. Vi behöver alltså inte sätta regler på INPUT för sådan trafik som initeras från oss själva.
Vi har inte sparat reglerna permanent, så om vi skulle låsa oss ute från servern kan vi starta om servern med hjälp av en kontrollpanel om vi har tillgång till en sådan. För att spara reglerna permanent använder vi kommandot iptables-save
och skickar utmatningen till en fil :
För att läsa in reglerna igen använder vi kommandot iptables-restore
tillsammans med filnamnet på den fil (som vi skapat med iptables-save
) vi vill läsa in :
Att administrera Netfilter med hjälp av iptables
är ganska krångligt och i Ubuntu finns det ett kommando som heter ufw
(Uncomplicated FireWall) som gör administrationen av brandväggen enklare.
Kommandot ufw status
visar status för brandväggen. När den är avstängd ser det ut så här:
Många av servertjänsterna vi installerar i Ubuntu kommer också lägga till profiler som innehåller information om hur brandväggen skall konfigureras. Eftersom vi har installerat SSH finns det en sådan profil att se:
För att se information om profilen använder vi kommandot ufw app info OpenSSH
, där OpenSSH är namnet på profilen som vi får fram med ufw app list
:
För att aktivera (tillåta) nätverkstrafik enligt profilen OpenSSH använder vi ufw allow
:
Här använder vi ssh
, men vi skulle kunna använda OpenSSH (som tjänsten heter i listan) också.
Nu sätter vi policyn för inkommande trafik till deny
:
För att aktivera brandväggen använder vi kommandot ufw enable
:
Nu kan vi se status för brandväggen med kommandot ufw status
:
Brandväggen är aktiverad och tillåter inkommande trafik till tjänsten ssh.
Vartefter vi installerar nätverkstjänster i Ubuntu (som till exempel webbservern Apache httpd) kommer vi få in fler policies i ufw app list
som vi kan aktivera.
Om vi vill öppna upp för trafik på en specifik port på vår server lägger vi till den med kommandot ufw
, låt oss lägga till port 80 med tcp-protokollet och port 53 med udp-protokollet:
Med kommandot ufw status verbose
kan vi se att port 80/tcp och port 53/udp är öppna (allow in).
I filen /etc/service
kan vi se alla kända portar och vilka protokoll de kör och vilka applikationer de tillhör.
Ibland vill vi öppna upp för en serie med nätverksportar. Låt oss säga port 20000 - 21000, då skulle vi kunna skriva så här:
I exemplet använder vi protokollet tcp, vill vi istället använda udp skriver vi 10000:20000/udp
. Vill vi lägga till både tcp och udp får vi göra det med två kommandon: ett för tcp och ett för udp.
Säg att vi har en specifik IP-adress som vi vill tillåta komma åt alla på portar på vår server, till exempel vår fasta IP- adress på kontoret. Då kör vi kommandot ufw allow from
och den IP-adress som vi vill tillåta:
Om det är en specik port, tjänst, som vi vill tillåta för IP-adressen lägger vi till to any port
, till exempel för ssh- tjänsten:
Om vi vill tillåta ett helt subnät kan vi ange det också. Säg att vi har ett kontorsnätverk - 192.168.1.0/24 - som vi vill tillåta ansluta till ssh-tjänsten. Då skriver vi följande kommando:
Om vi vill neka trafik till en specifik port (eller tjänst), eller en specik IP-adress använder vi deny
istället för allow
. Det kan se ut så här:
Vill vi ta bort regler vi skapat kan vi använda ufw delete
, tillsammans med tjänstens namn (ssh) eller port (22) :
Med kommandot ufw status numbered
får vi fram en lista över alla regler som är satta, dessa regler blir också numrerade:
Säg att vi vill ta bort blockeringen av port 80 för IP-adressen 1.2.3.4 i exemplet ovanför. Vi ser att det står [ 6]
i början av den raden. Det är regel nummer 6 och vi tar bort den genom att skriva:
Tittar vi på listan med regler igen, ser det ut så här:
Regeln för att blockera IP-adressen 1.2.3.4 från att komma åt port 80 är borttagen.
Om vi skulle vilja radera alla våra regler vi skapat i brandväggen kan vi köra kommandot ufw reset
, som tömmer regellistan:
När vi kör reset
kommer brandväggen också inaktiveras. För att starta den igen använder vi kommandot ufw enable
. Tänk på att vi inte har regeln för att komma åt ssh (port 22) som standard, så om vi aktiverar brandväggen på en server i en cloudtjänst kommer vi inte längre kunna ansluta till den servern med ssh.
Om vi vill behålla våra regler, men inaktivera brandväggen, kan vi använda kommandot ufw disable
. Det stänger ned brandväggen och tillåter all trafik in till servern, men behåller reglerna vi skapat - så nästa gång vi aktiverar brandväggen (ufw enable
) kommer reglerna att vara aktiverade.
När vi jobbar med brandväggar är en bra policy att vi låser ned allt (sätter policyn till deny eller drop) och öppnar upp så lite vi kan. SSH till exempel, är till för att vi skall kunna ansluta till servern och köra kommandon. Det behöver inte hela internet ha tillgång till. En webbserver däremot, där vi kör vår webbplats, behöver hela internet ha tillgång till. Så port 80 (http) och 443 (https) kanske behöver vara öppna på servern.
Kanske använder vi en jumpstation, en maskin som är uppsatt enbart för att vi skall kunna ansluta till den och sedan hoppa vidare, för att ansluta till ett privat nätverk i vår molntjänst eller i vårt datacenter. Därifrån kan vi sedan komma åt ssh på webbservern.
Även om vi använder en extern brandvägg, så som en hårdvaruappliance i datacentret eller en mjukvarubaserad i en molntjänst, är det bra att använda den lokala brandväggen på linuxservern också. Om någon kommer in i ditt privata nätverk (som körs i datacentret eller i molnet) behöver vi ju inte bjuda på full åtkomst överallt.
Ett exempel på konfiguration för en webbserver, där vi också vill kunna ansluta med ssh för att till exempel uppgradera Linux. I exemplet tänker vi oss att vi har IP-adressen 201.202.203.204 på vår egen maskin, så det är bara den som skall kunna ansluta till ssh.
Notera hur vi inaktiverar (disable) brandväggen först. Sedan ser vi till att vi öppnar upp för trafik mot port 22 (ssh) och webbservern (http och https) för att slutligen aktivera brandväggen (enable). Det här är en bra grundläggande konfiguration för en webbserver.
fail2ban
När vi har nätverksportar öppna ut mot internet kommer andra hitta oss. Det finns tusentals datorer ute på internet som letar efter öppna maskiner som de kan attackera och ta över. För att göra det lite svårare för dem kan vi använda ett program som heter fail2ban
, som är mycket effektivt på att stoppa intrångsförsök. fail2ban kan till exempel titta på misslyckade inloggningsförsök mot ssh-tjänsten och blockera IP-adressen som försöker logga in.
För att installera fail2ban använder vi kommandot apt
:
Konfigurationen av fail2ban
görs i katalogen /etc/fail2ban/
, där vi hittar en fil som heter jail.conf
. Eftersom den filen kan skrivas över av uppdateringar av fail2ban skapar vi en egen fil, jail.local
i samma katalog och där gör vi vår konfiguration. Allt som står i jail.local
-filen kommer gå över det som står i jail.conf
-filen.
Vi kan titta i filen jail.conf
för att se vad vi kan konfigurera, allt som står i filen kan vi skriva i vår jail.local
-fil. Filen har en global inställning som gäller för alla tjänster vi konfigurerar i fail2ban
, den globala inställningen hittar vi under [default]
. Sedan kommer olika avsnitt med konfiguration för en mängd olika tjänster som vi skulle kunna köra på vår server, nu är vi mest intresserade av [sshd]
.
Här kommer vi titta på hur vi kan skydda ssh-tjänsten från inloggningsförsök. Vårt mål blir att låsa ute alla som misslyckas logga in på ssh tre gånger under en timme och vi vill att de skall låsas ute 24 timmar.
Till att börja med kanske vi vill hindra oss själva från att bli utlåsta och det vill vi nog för alla tjänster vi kan skydda med fail2ban
, så vi skapar en ny fil jail.local
och skriver in följande i den:
Vi behöver också berätta för fail2ban att vi vill använda ufw för att hantera de blockerade IP-adresserna, det gör vi genom att ställa in actionban och actionunban:
Filen ufw.conf
kan vi titta i om vi vill se vad den gör, öppna i så fall filen /etc/fail2ban/action.d/ufw.conf
.
Sedan är det dags att skapa konfigurationen för ssh. Här ser vi till att kontrollen av ssh är aktiverad (enabled) och vi anger vilken port vi skall kontrollera (port). Vi anger också ett filter som innehåller de mönster fail2ban skall leta efter för att identifera misslyckade försök att komma åt tjänsten ssh. Vårt mål var låsa ute alla som misslyckats logga in på ssh tre gånger under en timme och vi skall låsa ut dem i 24 timmar. När vi anger tid till fail2ban är det i enheten sekunder. Så en timme blir 3600 sekunder och vi konfigurerar det med findtime
. Antalet försök som är tillåtna konfigurerar vi med maxretry
. Slutligen konfigurerar vi hur länge de skall vara utlåsta med bantime
, i vårt fall sätts det till 86400 sekunder som är 24 timmar.
När vi är klara skall filen jail.local
se ut så här:
För att läsa in konfigurationen startar vi om tjänsten fail2ban med kommandot systemctl
:
För att se att tjänsten är igång kan vi använda följande kommando:
Vi kan också titta i systemloggen efter meddelanden från fail2ban:
fail2ban loggar också till filen /var/log/fail2ban.log
där vi kan se lite mer vad som händer, till exempel med kommandot tail
:
För att se status på fail2ban använder vi kommandot fail2ban-client
:
Här kan vi se att vi har ett jail (varje applikation vi övervakar kallas jail) aktivt och att det är sshd. Vill vi se status för ett specifikt jail, till exempel sshd ovanför, skriver vi så här:
Under Actions ser vi hur många IP-adresser vi har som är blockerade (banned), i det här fallet har vi inga alls. De kommer dyka upp om de gör tre misslyckade inloggningsförsök till tjänsten ssh under en och samma timme. Precis som vi konfigurerade fail2ban.
Diskar och filsystem
En hårddisk
En hårddisk är uppbyggd av flera elektromagnetiska skivor som sitter på en axel. En läs- och skrivarm rör sig hela tiden över de roterande skivorna.
Hantera partitioner
Det finns flera olika sätt att partionera lagringsmedia i Linux. Vi kommer titta på två av dem: fdisk
och cfdisk
.
fdisk
För att se alla partitioner vi har på hårddiskar som är anslutna till datorn kan vi använda kommandot fdisk -l
:
Ett annat sätt att visa diskar och partitioner är att använda kommandot lsblk
:
För att hantera en disk med kommandot fdisk
startar vi fdisk med diskens namn:
p
visar partitioner på diskenm
visar hjälpn
skapar en ny partitionq
avslutar fdisk
Var säker på vad du gör med fdisk, för gör du fel kan du förlora data på din disk! |
cfdisk
Kommandot fdisk
är lite omständigt att jobba med. Ett alternativ är att använda kommandot cfdisk
som är enklare. Vi startar det på samma sätt som vi startade kommandot fdisk :
?
ger oss hjälpq
avslutar
Filen /etc/fstab
Filen /etc/fstab
innehåller information om hur och var diskar och nätverksenheter (NFS, CIFS, ..) skall monteras i filsystemsträdet. Filen används av systemet för att hitta vilka diskar som skall monteras vid uppstart av systemet och vi kan också skapa egna monteringspunkter till enheter som vi vill montera enklare.
Filen består av flera rader med sex fält som är separerade med mellanslag eller tabb:
Fälten:
- /dev/sda1 är enheten. Det kan vara /dev/sda1 som här, eller en UUID eller en LABEL.
- / är monteringspunkten, det är här filsystemet kommer monteras i filsystemsträdet.
- ext4 anger filsystemet
- defaults anger alternativ till filsystemet. Här kan vi ibland hitta
ro
(read-only),rw
(read-write) och andra alternativ. - 0 hör ihop med ett kommando som heter
dump
, en nolla här betyder attdump
inte skall göra backup på filsystemet. - 0 anger vilken ordning filsystemet skall kontrolleras vid uppstart. / bör ha en 1:a här, andra monteringspunkter bör ha en 2:a om de skall kontrolleras, eller en 0:a om de install kontrolleras.
För att montera alla filsystem som definerats i filen /etc/fstab
skriver vi:
Vill bara montera /home
som vi definerat i filen /etc/fstab
skriver vi:
RAID
Redundant Array of Independent Disks (när RAID kom hette det Inexpensive och inte Independent, vilket man kan läsa och höra fortfrande).
RAID är indelade i olika nivåer och de vanligaste nivåerna vi använder är:
- RAID 0 - Stripe set
- RAID 1 - Mirroring
- RAID 5 - Stripe set med paritet
- RAID 6 - Stripe set med dubbel paritet
- RAID 10 - Mirroring och stripe set
RAID 0 - Stripe Set
Stripe set är den enklaste formen av RAID vi kan använda. För att bygga en stripe set behöver vi minst två diskar och tekniken fungerar så att när vi skriver data till stripe setet skrivs det första blocket på disk 1, det andra blocket på disk 2, det tredje blocket på disk 1, och så vidare. Fördelen med stripe set är att vi ökar hastigheten på diskläsningar och -skrivningar eftersom vi sprider ut datat på flera diskar. Vi får också en större volym att lagra data på.
Om vi har två stycken två (2) terabyte stora diskar och sätter upp dem i en stripe set kommer vi få en volym om fyra (4) terabyte där vi kan lagra data.
Nackdelen med stripe set är att om en av diskarna som ingår i volymen går sönder förlorar vi all data på hela volymen. Därför kom RAID 5 och RAID 6 som erbjuder stripe set med paritet.
Ibland kan vi se begreppet JBOD, Just a Bunch Of Disks, i samband med RAID-lösningar. JBOD fungerar i princip som RAID 0, med skillnaden att data skrivs först på disk 1 tills den blir full, då fortsätter vi skriva på disk 2. Tills den blir full. Fördelen med JBOD är att vi kan få större volymer att lagra data på eftersom vi slår ihop flera diskar till en och samma volym.
RAID 1 - Mirroring
Med mirroring speglar vi data på två diskar. Mirroring kräver minst två (2) diskar och all data som skrivs på disk 1 skrivs också på disk 2. Det här gör att om den ena disken går sönder så finns vår data kvar på den andra disken.
RAID 5 - Stripe set med paritet
I RAID 5 använder vi minst tre (3) diskar och bygger en stripe set på dem (som i RAID 0). Vi får partitet på stripe setet vilket är kontrolldata som sprids på diskarna. Om en disk går sönder kan vi återskapa data som fanns på den disken genom att använda data och partitet som finns på de andra diskarna.
RAID 5 är vanlig i servrar eftersom det erbjuder både bra prestanda på läsningar och en viss dataintegritet i och med pariteten. Pariteten använder lika mycket utrymme som en disk, men är utspridd över alla diskarna, vilket innebär att vi tappar en disks lagringskapacitet.
Om vi har tre (3) stycken två (2) terabytes diskar och använder RAID 5 på dem kommer vi alltså att ha fyra (4) terabyte utrymme att lagra data på, trots att de tre diskarna tillsammans blir sex (6) terabyte.
RAID 6 - Stripe set med dubbel paritet
RAID 6 fungerar i princip som RAID 5, men i RAID 6 utökas pariteten till den dubbla. Pariteten skrivs på två ställen i volymen och vi förlorar således utrymme motsvarande två (2) diskar. Det här betyder att två diskar kan gå sönder utan att vi har dataförlust. För att kunna använda RAID 6 behöver vi ha minst fyra (4) diskar.
Om vi har fyra (4) stycken två (2) terabytes diskar och använder RAID 6 på dem kommer vi ha fyra (4) terabyte att lagra data på, de andra två (2) terabyten används för pariteten.
RAID 10 - Mirroring och stripe set
I RAID 10 (ibland kallat RAID 1+0) kombinerar vi speglingen från RAID 1 med stripe set från RAID 0. Det betyder att vi speglar en stripe set. För att kunna göra detta behöver vi minst fyra diskar som vi delar upp i par om två och två där vi kör stripe set på det ena paret och speglar det till det andra paret.
Fördelen med den här lösningen är att det krävs mycket innan vi skall ha dataförlust på vår volym. Nackdelen är naturligtvis att lösningen är dyr, vi behöver dubbelt så mycket disk mot vad vi kan lagra på dem.
Om vi har fyra (4) stycken två (2) terabyte stora diskar och använder RAID 10 på dem kommer vi kunna lagra fyra terabyte data på dem. De fyra terabyte som vi inte kan använda för datalagring är speglingen.
Logical Volume Manager (LVM)
Logical Volume Manager (LVM) är ett verktyg för att hantera virtuella lagringsenheter (hårddiskar). LVM består av tre delar: Physical Volume (PV), Volume Group (VG) och Logical Volume (LV). Physical Volume motsvarar de fysiska enheterna, som till exempel en hårddisk. En Volume Group innehåller en eller flera Physical Volumes för att bilda en lagringspool, från vilken vi kan skapa Logical Volumes.
Skapa Physical Volumes
Vi kan också ange alla enheterna på en och samma rad:
För att se att vår Physical Volume skapades kan vi använda kommandot pvdisplay
, här visar vi bara enheten /dev/vdb
:
Vill vi visa alla Physical Volumes vi har skriver vi bara pvdisplay
:
Nu behöver vi lägga till våra Physical Volumes i en Volume Group.
Skapa Volume Group
The valid characters for VG and LV names are: a-z A-Z 0-9 + _ . - får inte börja med -
Skapa Logical Volume
Vi skapar en logical volume med kommandot lvcreate
:
Skapa ett filsystem
När vi partionerat vår disk måste vi skapa ett filsystem på partitionen innan vi kan börja använda disken. Vi använder kommandot mkfs
för att skapa filsystem i Linux.
Linux har stöd för många olika typer av filsystem, en del kan vara inkompilerade i kärnan och andra kan finnas tillgängliga som moduler. Modulerna, som kan ses som drivrutiner, finns listade i katalogen /lib/modules/DIN_VERSION/kernel/fs
[footnote:Du får fram din kärnas versionsnamn med kommandot `uname -r]. Vi kommer titta på ett par stycken av dessa filsystem: ext2, ext3 och ext4, iso9660, UDF, FAT och NTFS.
Ett journalförande filsystem innebär att filsystemet håller en journal över förändringarna som sker i filsystemet. När vi sparar en fil till filsystemet håller filsystemet reda på hur långt det kommit med skrivningen och skulle systemet krascha eller plötsligt dö kommer journalen användas för att kontrollera filsystemet och återställa det till ett korrekt tillstånd. Vi behöver alltså inte köra en komplett filsystemskontroll på ett journalförande filsystem, vilket innebär att vi minskar tiden som krävs för att komma igång efter en krasch igen.
Linux har stöd för flera olika typer av filsystem som används över nätverk. Bland annat Network File System (NFS) och Common Internet File System (CIFS) som används av Windows. Ibland kan man höra talas om Samba som är den äldre varianten av CIFS.
ext2, ext3 och ext4
Ext2, second extended filesystem, var det filsystem som gällde i Linux under många år. Ext2 är ett ett ganska enkelt filsystem som har stöd för rättigheter på filnivå. Idag används ext2 enbart i specialfall, eftersom ext4 ersatt det.
Ext3, third extended filesystem, är ett journalförande filsystem. Filsystemet lagrar information om filer och kataloger i inoder. I en inode finns information om hur stor filen är, vilken enhet filen finns på, vem som äger filen, vilken grupp filen tillhör, vilka rättigheter som är satta på filen, vilken tid filen skapades (ctime), när den senast förändrades (mtime) och när den senast användes (atime), vilka länkar som pekar på filen och slutligen var på enheten filen ligger lagrad.
- Filnamnen kan bestå av 255 bytes.
- Filnamnen är skiftlägeskänsliga.
- Filstorleken kan vara upp till 2 TiB.
- Den största volymstorleken som kan skapas är 16 TiB.
- Ext3 är ett journalförande filsystem.
- Ext4, fourth extended filesystem, är en utökning av filsystemet ext3 vilket innebär att det också är ett journalförande filsystem. Den stora skillnaden mellan ext3 och ext4 är prestandaökningar och bättre hantering av fragmentering (filerna hålls ihop på disken). Ext4 ger också stöd för större filsystem, upp till 1 EiB (exabyte).
- Filnamnen kan bestå av 255 bytes.
- Filnamnen är skiftlägeskänsliga.
- Filstorleken kan vara upp till 16 TiB.
- Den största volymstorleken som kan skapas är 1 EiB (exabyte).
- Ext4 är ett journalförande filsystem.
- Bättre prestanda än ext3.
iso9660
ISO9660 är det filsystem som används på CD-ROM skivor. ISO9660 är indelad i tre nivåer där Level 1 är den ursprungliga standarden som stödjer 8.3 tecken, dvs åtta tecken i filnamnet och tre tecken i en filändelse. Level 2 och Level 3 utökar detta till 255 tecken.
- Filnamnen kan vara 8.3 tecken långa (Level 1) och upp till 180 tecken (Level 2 och Level 3)
- Filstorleken på lagrade filer kan vara 4 GiB (Level 1 och Level 2) och 8 TiB (Level 3)
- Den största partitionen vi kan skapa med ISO9660 är 8 TiB
UDF
Universal Disk Format Filesystem (UDF) är ett filsystem som ofta används på CD-RW (läs/skrivbara skivor) och DVD.
- Filnamn kan vara 255 tecken långa.
- Filstorleken kan vara 16 EiB.
- Partitionerna kan vara 2 TiB på hårddiskar och 8 TiB på optisk media.
FAT
FAT, eller File Allocation Table, finns i tre olika varianter: FAT12, FAT16 och FAT32. På en FAT-volym kan man som mest ha 512 filer i rotkatalogen, i underkataloger kan vi ha upp till 65 535 filer per katalog. En FAT-volym kan vara 8 TiB stor och lagra filer som är mest 4 GiB stora.
Filallokeringstabellen (FAT) innehåller information om filnamnet, filattributen, filstorlek, när filen senast förändrades och vilket kluster filen börjar på. FAT har saknar säkerhet och vi kan inte sätta rättigheter på filer och kataloger i FAT. FAT har stöd för filattribut som read-only, hidden, system och archive. Read-only innebär att filen är skrivskyddad och enbart går att läsa, hidden innebär att filen är dold, system att det är en systemfil och archive är en flagga som sätts när filen är arkiverad. Archive används av backup-program.
FAT har stöd för 8.3 tecken i filnamnen. Det innebär att filnamnet kan vara åtta (8) tecken och ha en filändelse på tre (3) tecken. Med stödet för långa filnamn (VFAT) kan vi ha upp till 255 tecken totalt i filnamnet. Den enda fördelen FAT har jämfört med NTFS är på små diskar (under 512 MiB), har vi en disk som är större än 512 MiB bör vi köra NTFS om vi kör operativsystemet Microsoft Windows.
I Linux heter modulen för att få stöd för FAT just fat
. För att få stöd för långa filnamn laddar vi istället modulen vfat
. Linux klarar av att både läsa och skriva till FAT.
- Filnamnen kan vara 8.3 tecken eller 255 tecken om man har stöd för utökade filnamn.
- Filnamnen är inte skiftlägeskänsliga.
- Filstorleken kan vara: FAT12–32 MiB, FAT16–2 GiB och FAT32–4 GiB.
- Den största volymstorleken som kan skapas är: FAT12–32 MiB, FAT16–2 GiB och FAT32–8 TiB.
NTFS
NTFS, New Technology File System, kom första gången i Windows NT4. NTFS är ett journalförande filsystem och informationen om filerna som filnamnet, storleken och rättigheter lagras i en Master File Table (MFT).
NTFS har stöd för filkompression, vilket innebär att en fil som sparas på enheten komprimeras automatiskt (om du aktiverat det). NTFS känner också själv av trasiga sektorer i filsystemet och flyttar filer därifrån och markerar sektorerna som skadade.
NTFS 3.0, den version som kom med Windows 2000, erbjuder en del utökningar till NTFS som Encrypted File System (EFS), Quota och stöd för att montera enheter i kataloger (Volume Mount Point).
I de versioner av Windows som stödjer NTFS kan vi konvertera ett FAT-filsystem till NTFS med hjälp av kommandot convert
.
Linux har ett bra stöd för att läsa NTFS-filsystem, men har lite svårare med att skriva till dem. Det finns idag en del möjligheter att skriva till ett NTFS-filsystem i Linux - men det finns inget riktigt stabilt sätt. Modulen för att läsa NTFS heter ntfs
.
- Filnamnen kan vara 254 tecken långa, filändelsen skiljs åt med en punkt.
- Filnamnen är inte skiftlägeskänsliga.
- Filstorleken kan vara 16 EiB.
- Den största volymstorleken som kan skapas är 16 EiB.
- NTFS är ett journalförande filsystem.
Mjuka- och hårda länkar
I Linux kan vi skapa mjuka- och hårda länkar i filsystemet. Vi kan se länkar som de genvägar som vi kan skapa i Windows. Istället för att behöva komma ihåg hela sökvägen till en katalog eller en fil skapar vi en genväg till den.
En mjuk länk (symbolic link) är en länk som kan peka på en fil eller en katalog vart som helst i filsystemet. En hård länk (hard link) kan enbart pekas på filer inom samma partition i filsystemet.
Övning - skapa en logisk volym
För den här övningen behöver vi skapa tre filer som är 1 GiB stora, vi använder ett kommando som heter fallocate
:
Om vi saknar kommandot fallocate
behöver vi installera paketet util-linux
:
Nu har vi tre filer som vi skall använda som diskar. Vi skapar loopback-devices av dem med kommandot losetup
:
För att kunna skapa en logisk volym behöver vi först skapa physical volumes (pv), så vi använder kommandot pvcreate
för detta:
När vi skapat våra tre physical volumes skall vi skapa en volume group av dem, här skapar vi en volume group med namnet VG_TEST
som innehåller de tre physical volumes vi skapade precis:
För att visa vår volume group använder vi kommandot vgdisplay
:
När vår volume group är skapad är det dags att skapa en logical volume från den, det gör vi med kommandot lvcreate
och här skapar vi en 500 MiB stor logical volume som vi döper till DATA:
När den logiska volymen är skapad behöver vi formattera den med ett filsystem, vi använder kommandot mkfs
för detta:
Nu när vi har ett filsystem på den logiska volymen kan vi montera, och använda, det. Vi skapar en katalog som vi skall använda för att montera filsystemet i:
Sedan monterar vi filsytemet:
Kommandot df
kan visa oss hur stor volymen är:
Och kommandot mount
visar vilket filsystem volymen är formatterad med:
Det var det, nu är det dags att städa upp, vi börjar med att avmontera katalogen /mnt/data
. Om detta inte fungerar beror det ofta på att vi är i katalogen, skriv bara cd
först för att komma till din hemkatalog så löser det sig ofta:
Sedan raderar vi den logiska volymen med kommandot lvremove
:
Vi har en volume group att radera också, det gör vi med kommandot vgremove
:
Volymgruppen byggde vi med tre stycken physical volumes, som vi raderar med kommandot pvremove
:
Och slutligen skall vi radera de loopback-devices som vi skapade: