1.4 Werken in de terminal

OpmerkingLeerdoelen

Na deze les kan je:

  • de bouw van een commando uitleggen: de naam, de opties en de argumenten
  • het bestandssysteem beschrijven als een boom en een pad erin lezen
  • je verplaatsen met pwd, ls en cd
  • een map maken, een bestand schrijven in micro en het uitvoeren met python3
  • kopiëren, hernoemen en verwijderen met cp, mv, rm en rmdir, en uitleggen waarom verwijderen definitief is
  • tab-aanvulling en pijl omhoog gebruiken

Je programmeert in een Linux virtuele machine op je Chromebook. Je bedient die niet met knoppen maar met getypte commando’s. Het venster waarin je typt heet de terminal, en het programma daarin dat je commando’s leest en uitvoert heet de shell. In deze les leer je een commando lezen, je verplaatsen tussen mappen, en een Pythonbestand schrijven en uitvoeren.

Voor deze les: zet de Linux-omgeving aan via Instellingen, Over ChromeOS, Linux-ontwikkelomgeving. Kies 10 GB schijfruimte. Wacht enkele minuten tot de virtuele machine geïnstalleerd is. Open daarna de app Terminal uit het overzicht van apps en installeer de teksteditor micro, het naslagwerk tldr en het programma tree.

sudo apt update
sudo apt install micro tealdeer tree
tldr --update

Bij de vraag Continue? [Y/n] druk je op y.

1 De bouw van een commando

Bijna alle commando’s hebben dezelfde bouw: eerst de naam, dan de opties, dan de argumenten, gescheiden door spaties. De naam zegt wat er moet gebeuren, de opties hoe, en de argumenten waarop. Opties en argumenten zijn niet verplicht. Je herkent een optie aan het streepje: één streepje voor een letter, zoals -l, twee streepjes voor een woord, zoals --help.

pwd
ls -l
python3 oefening1.py
ls -l /home/<naam>/iw6
WaarschuwingOpgelet

De spatie is het scheidingsteken tussen de naam, de opties en de argumenten, dus een bestandsnaam met een spatie erin telt als twee argumenten.

Schrijf een naam uit meerdere woorden met koppeltekens, zoals

python3 mijn-eerste-oefening.py

of zet de naam tussen enkele aanhalingstekens

python3 'mijn eerste oefening.py'

of schrijf \ voor de spaties zodat ze als letter worden gelezen.

python3 mijn\ eerste\ oefening.py

Een gelijkaardig probleem uit Vlaamse wiskundenotatie: In \((1,2)\) scheidt de komma de twee coördinaatgetallen. In \((1{,}1; 2)\) is de komma al bezet als decimaalteken, en wordt de puntkomma het scheidingsteken.

2 Het bestandssysteem is een boom

Alle bestanden en mappen samen vormen een boom. De bovenste map heet de root. Elke map kan mappen en bestanden bevatten. Zo ziet je thuismap eruit op het einde van deze les.

/
├── etc
├── home
│   └── <naam>
│       └── iw6
│           └── oefeningen
│               ├── oefening1.py
│               └── oefening2.py
└── usr

flowchart TD
    root["/"] --> etc["etc"]
    root --> home["home"]
    root --> usr["usr"]
    home --> leerling["#lt;naam#gt;"]
    leerling --> iw6["iw6"]
    iw6 --> oefeningen["oefeningen"]
    oefeningen --> oefening1(["oefening1.py"])
    oefeningen --> oefening2(["oefening2.py"])
    style leerling stroke-width:3px

<naam> staat op deze pagina voor jouw gebruikersnaam. De map met die naam is je thuismap. Je begint daar telkens als je een terminal opent.

Een pad is een route door de boom, met / als scheidingsteken tussen de mapnamen. Een pad dat met / begint, vertrekt bij de root en wijst altijd dezelfde plaats aan. Dit heet een absoluut pad.

/home/<naam>/iw6/oefeningen/oefening1.py

vergelijk met

Victor Frislei 18
2900 Schoten
België

Een pad dat niet met / begint, vertrekt bij de map waar je bent. Dit heet een relatief pad.

iw6/oefeningen/oefening1.py

vergelijk met

Van hier eerste links
dan tweede rechts
en dan het eerste huis voorbij de sporthal

Vier afkortingen komen in paden voor. / is de root, ~ is je thuismap, . is de map waar je bent en .. de map één niveau hoger.

BelangrijkBelangrijk

In een boom bestaat er per definitie tussen elke twee knopen precies één pad.

3 Waar je bent: pwd, ls en cd

Open de app Terminal. Vanaf hier typ je elk consoleblok letterlijk over, regel per regel, en druk je op enter. Wat je daarna ziet, staat in de tekst eronder.

clear maakt het scherm leeg. Je bestanden en de map waar je bent veranderen niet.

clear

pwd staat voor print working directory en toont de map waar je bent, je werkmap.

pwd

Je ziet /home/ gevolgd door je gebruikersnaam. Voor alles wat je typt staat de prompt: je gebruikersnaam, de naam van de machine en de map waar je bent, gevolgd door $.

ls staat voor list en toont de inhoud van de werkmap. Een lege map geeft geen uitvoer, en je thuismap is nog leeg.

ls

Er verschijnt niets.

cd staat voor change directory. Je gaat ermee naar een andere map. cd .. gaat één niveau omhoog, cd zonder argument gaat naar je thuismap, en cd - naar de map waar je daarvoor was.

cd ..
ls

De prompt toont nu /home, en ls toont je gebruikersnaam.

cd

De prompt toont weer ~.

BelangrijkBelangrijk

Een commando werkt op de map waar je bent, tenzij je een pad meegeeft. ls toont de werkmap, ls /etc toont /etc. Vind je een bestand niet terug, controleer dan eerst met pwd in welke map je bent.

4 Een map maken, een bestand schrijven en uitvoeren

mkdir staat voor make directory en maakt een map met de naam die je als argument geeft. mkdir geeft geen uitvoer. De meeste commando’s die iets doen, geven geen uitvoer als ze slagen. Je krijgt enkel een nieuwe prompt. Enkel bij een fout verschijnt er een foutmelding.

mkdir iw6
cd iw6

De prompt toont nu ~/iw6.

mkdir oefeningen
ls

ls toont oefeningen.

micro opent het bestand dat je als argument geeft. Als dat bestand nog niet bestaat, maakt micro het aan. In micro typ je de code van je programma. Ctrl-S bewaart het bestand en Ctrl-Q sluit micro af. Daarna ben je terug in de terminal.

micro oefeningen/oefening1.py

Typ in micro de ene regel print("Hallo"), bewaar en sluit af.

python3 voert een Pythonbestand uit. Het argument is de naam van het bestand.

python3 oefeningen/oefening1.py

Je ziet Hallo.

Een foutmelding vermeldt het bestand, het regelnummer en het stuk van de regel waar het misloopt.

micro oefeningen/oefening2.py

Typ in micro de ene regel print(naam), bewaar en sluit af.

python3 oefeningen/oefening2.py

Je ziet deze foutmelding, met jouw gebruikersnaam in het pad:

Traceback (most recent call last):
  File "/home/<naam>/iw6/oefeningen/oefening2.py", line 1, in <module>
    print(naam)
          ^^^^
NameError: name 'naam' is not defined

tree toont een map en alles eronder als boom. Op een Belgisch toetsenbord typ je ~ met AltGr en =, gevolgd door een spatie.

tree ~

Je ziet de boom uit sectie 2 vanaf /home/<naam>, met eronder het aantal mappen en bestanden. Je bent in ~/iw6, en vanuit die map wijzen deze paden naar wat je net maakte.

pad wijst aan
/home/<naam>/iw6/oefeningen/oefening1.py oefening1.py, waar je ook bent
oefeningen/oefening1.py hetzelfde bestand, vanuit iw6
oefeningen de map oefeningen in iw6
. /home/<naam>/iw6
.. /home/<naam>
~/iw6/oefeningen/oefening2.py oefening2.py, waar je ook bent

5 Kopiëren, hernoemen en verwijderen

WaarschuwingOpgelet

De terminal heeft geen prullenbak. Een bestand dat je verwijdert of overschrijft, is definitief weg. Kijk met ls na of een naam nog vrij is voor je ze gebruikt.

cp staat voor copy. Het eerste argument is het bestand dat je kopieert, het tweede de naam van de kopie. cp overschrijft een bestaand bestand zonder waarschuwing.

cp oefeningen/oefening1.py oefeningen/oefening1.py.bak
ls oefeningen

Je ziet oefening1.py oefening1.py.bak oefening2.py.

De extensie .bak, van backup, markeert een reservekopie. Voor de shell is het een gewoon bestand. Maak zo’n kopie voor je iets uitprobeert waarvan je niet zeker bent.

mv staat voor move en verplaatst een bestand. Hernoemen gebeurt met hetzelfde commando. Ook mv overschrijft een bestaand bestand zonder waarschuwing.

mv oefeningen/oefening1.py.bak oefeningen/kopie.py
mv oefeningen/kopie.py .
ls

Je ziet kopie.py oefeningen. De eerste mv hernoemt de kopie, de tweede verplaatst ze naar ., de map waar je bent.

rm staat voor remove en verwijdert een bestand. rm werkt niet op een map. rmdir staat voor remove directory en verwijdert een map, maar enkel een lege.

rm kopie.py
rm oefeningen
rmdir oefeningen

De eerste regel geeft geen uitvoer. De tweede en de derde geven een foutmelding:

rm: cannot remove 'oefeningen': Is a directory
rmdir: failed to remove 'oefeningen': Directory not empty

Deze twee foutmeldingen voorkomen dat één verkeerd getypt argument een volledige map verwijdert. Geef rm de optie -r mee, van recursive, om een map met inhoud te verwijderen. Kijk eerst met ls wat erin staat.

mkdir oud
cp oefeningen/oefening2.py oud
ls oud
rm -r oud
ls

De eerste ls toont oefening2.py, de tweede enkel oefeningen. Is het tweede argument van cp een map, dan komt de kopie in die map, met dezelfde naam.

6 Minder typen

De shell vult aan wat je begon te typen als je op tab drukt. Een tweede tab toont alle mogelijkheden als er meer dan één naam past. Tab werkt op commando’s, mappen en bestanden en vult enkel bestaande namen aan. Als tab niets aanvult, bevat de regel een typfout.

Typ cd oef en druk op tab. De regel wordt cd oefeningen/. Druk op enter. De prompt toont nu ~/iw6/oefeningen.

De pijl omhoog haalt een vorig commando terug, het laatste eerst. Je kan de regel aanpassen voor je op enter drukt.

python3 oefening1.py

Je ziet Hallo. Druk op de pijl omhoog en op enter. Je ziet opnieuw Hallo.

tldr gevolgd door een commando toont enkele voorbeelden van hoe je het gebruikt.

tldr cp

7 Conclusie

Een commando bestaat uit een naam, opties en argumenten. Het bestandssysteem is een boom met / als root, ~ als je thuismap, . als de map waar je bent en .. als de map één niveau hoger. Een absoluut pad vertrekt bij de root, een relatief pad bij de map waar je bent. Met pwd, ls en cd weet je waar je bent en ga je naar een andere map. Met mkdir, micro en python3 maak je een map, schrijf je een programma en voer je het uit. Met cp, mv en rm kopieer, verplaats en verwijder je, zonder prullenbak.

8 Begrippen

  • terminal (terminal): het venster waarin je typt en waarin de uitvoer verschijnt.
  • shell (shell): het programma in de terminal dat je commando’s leest en uitvoert.
  • commando (command): een opdracht aan de computer, bestaande uit een naam, eventuele opties en eventuele argumenten.
  • optie (option, flag): een aanpassing van wat een commando doet, herkenbaar aan een streepje, zoals -l.
  • argument (argument): datgene waarop een commando werkt, meestal een bestand of een map.
  • scheidingsteken (delimiter): het teken dat de delen van een geheel uit elkaar houdt, zoals de spatie in een commando en / in een pad.
  • prompt (prompt): het begin van elke regel die je typt, hier <naam>@penguin:~$, met je gebruikersnaam, de machine en de map waar je bent.
  • map (directory, folder): een plaats in de boom die bestanden en andere mappen kan bevatten.
  • bestand (file): bevat gegevens, geen mappen of andere bestanden.
  • boom (tree): de structuur van alle mappen en bestanden samen, waarin alles onder één root valt.
  • root: de bovenste map, geschreven als /.
  • thuismap (home directory): de map die van jou is, afgekort als ~.
  • pad (path): een route door de boom, met / als scheidingsteken tussen de mapnamen.
  • absoluut pad (absolute path): een pad dat met / begint en dus bij de root vertrekt.
  • relatief pad (relative path): een pad dat niet met / begint en dus bij de map waar je bent vertrekt.
  • werkmap (working directory): de map waar je bent.

9 Oefeningen

  1. Wijs in ls -l /etc het commando, de optie en het argument aan.

    ls is het commando, -l is de optie en /etc is het argument.

  2. Gebruik de boom uit sectie 2. Je bent in /home/<naam>/iw6/oefeningen. Beantwoord zonder terminal.

    1. Schrijf het relatieve pad naar oefening2.py.
    2. Schrijf het absolute pad naar hetzelfde bestand.
    3. Waar wijst ../oefening1.py naar, en bestaat dat?
    4. Schrijf twee verschillende commando’s die je naar je thuismap brengen.

    a. oefening2.py. Het bestand zit in de map waar je bent.

    b. /home/<naam>/iw6/oefeningen/oefening2.py.

    c. Naar /home/<naam>/iw6/oefening1.py, want .. is iw6. Dat bestand bestaat niet. oefening1.py zit in oefeningen, niet in iw6.

    d. cd ../.. gaat twee niveaus omhoog. cd zonder argument doet hetzelfde, en cd ~ en cd /home/<naam> eveneens.

  3. Je bent in /home/<naam>/iw6. Maak een map archief, verplaats oefening2.py daarheen, en maak in oefeningen een kopie van oefening1.py met de naam oefening1-kopie.py. Controleer met tree ~ dat je thuismap er daarna zo uitziet:

    /home/<naam>
    └── iw6
        ├── archief
        │   └── oefening2.py
        └── oefeningen
            ├── oefening1-kopie.py
            └── oefening1.py
    mkdir archief
    mv oefeningen/oefening2.py archief
    cp oefeningen/oefening1.py oefeningen/oefening1-kopie.py
    tree ~
  4. Drie dingen die mislopen. Voorspel telkens wat er verschijnt, probeer het daarna uit, en verklaar het verschil met wat je verwachtte.

    1. Ga naar oefeningen en typ daar python3 oefeningen/oefening1.py.
    2. Verwijder in oefening1.py het sluitende haakje en voer het bestand opnieuw uit. Vergelijk de foutmelding met die uit sectie 4.
    3. Typ cd ie en druk op tab.

    a. python3: can't open file '/home/<naam>/iw6/oefeningen/oefeningen/oefening1.py': [Errno 2] No such file or directory. Het pad is relatief en vertrekt bij de map waar je bent. Vanuit oefeningen wijst oefeningen/oefening1.py naar een map oefeningen in oefeningen, en die bestaat niet. Vanuit deze map is het pad gewoon oefening1.py.

    b.

      File "/home/<naam>/iw6/oefeningen/oefening1.py", line 1
        print("Hallo"
             ^
    SyntaxError: '(' was never closed

    Er staat geen Traceback boven. Python controleert een bestand eerst volledig op schrijffouten en voert het pas daarna uit. Deze fout komt dus aan het licht voor de uitvoering begint, en zonder uitvoering is er geen Traceback.

    c. Er gebeurt niets, want er is geen map die met ie begint. Tab vult enkel bestaande namen aan.

  5. Teken op papier de boom vanaf je thuismap, met alles wat je daarin maakte. Controleer daarna met tree ~.

    /home/<naam>
    └── iw6
        ├── archief
        │   └── oefening2.py
        └── oefeningen
            ├── oefening1-kopie.py
            └── oefening1.py