Bash Scripting
Een shell script is een tekstbestand met een reeks commando's die de shell achter elkaar uitvoert. Scripts automatiseren repetitieve taken: bestanden verwerken, back-ups maken, servers configureren. Als je een reeks commando's meer dan twee keer uitvoert, schrijf je er een script voor.
Je eerste script
Maak een bestand hello.sh aan:
#!/bin/bash
echo "Hallo, wereld!"
De eerste regel — #!/bin/bash — heet de shebang. Ze vertelt het systeem welke interpreter het script moet uitvoeren. /bin/bash is dezelfde bash-shell die we eerder hebben ingesteld als standaard shell voor gebruikers (het laatste veld in /etc/passwd). Zonder de shebang weet het systeem niet welke taal het script spreekt.
Maak het script uitvoerbaar en voer het uit:
chmod +x hello.sh # Geef uitvoerrechten (zie het hoofdstuk Gebruikers & Rechten)
./hello.sh # Voer uit — de ./ geeft aan dat het in de huidige map staat
De ./ voor de naam is nodig omdat Linux scripts in de huidige map niet automatisch uitvoert (om veiligheidsredenen). Je geeft expliciet aan: "dit bestand, hier in deze map".
Variabelen
Variabelen zijn containers die een waarde bewaren, zodat je die later kunt hergebruiken zonder ze opnieuw te typen. In bash wijs je een waarde toe met = en lees je die uit met $.
naam="Linux"
echo "Hallo, $naam!" # Output: Hallo, Linux!
echo "Hallo, ${naam}!" # Met accolades — zelfde resultaat
echo "Versie: ${naam}2" # Werkt correct: "Versie: Linux2"
echo "Versie: $naam2" # Fout: bash zoekt variabele '$naam2'
Regels om te onthouden:
- Geen spaties rond het
=-teken:naam="Linux"✓,naam = "Linux"✗ - Namen zijn hoofdlettergevoelig:
naamenNAAMzijn twee verschillende variabelen - Gebruik
${var}wanneer de variabelenaam direct gevolgd wordt door tekst
Command substitution
Met $(...) voer je een commando uit en sla je de uitvoer op als variabele. Dit is een van de krachtigste patronen in bash scripting.
datum=$(date +%Y-%m-%d)
echo "Vandaag is het $datum"
# Output: Vandaag is het 2025-06-01
aantal=$(ls | wc -l)
echo "Er staan $aantal bestanden in deze map."
gebruiker=$(whoami)
echo "Je bent ingelogd als $gebruiker"
Argumenten
Je kunt waarden meegeven aan een script via argumenten — net zoals je ls -la /etc typt met argumenten. Binnen het script zijn de argumenten beschikbaar als speciale variabelen.
#!/bin/bash
echo "Scriptnaam: $0"
echo "Eerste argument: $1"
echo "Tweede argument: $2"
echo "Alle argumenten: $@"
echo "Aantal argumenten: $#"
./script.sh Alice Bob
# Scriptnaam: ./script.sh
# Eerste argument: Alice
# Tweede argument: Bob
# Alle argumenten: Alice Bob
# Aantal argumenten: 2
Argumenten maken je script herbruikbaar. In plaats van de mapnaam hardcoded in het script te zetten, geef je hem mee als argument — zo werkt het script voor elke map.
Condities
Met if voer je code enkel uit als een bepaalde voorwaarde geldig is. De conditie staat tussen [ en ], gevolgd door then. Het blok sluit altijd af met fi (omgekeerd van if).
if [ conditie ]; then
# commando's als de conditie waar is
elif [ andere-conditie ]; then
# commando's als de eerste conditie onwaar is maar deze waar
else
# commando's als geen enkele conditie waar is
fi
Testoperatoren
De conditie test iets — een bestand, een string of een getal. Hier zijn de meest gebruikte operatoren:
Bestandstests — controleer of iets bestaat of leesbaar is:
| Operator | Betekenis |
|---|---|
-f bestand | Bestaat als gewoon bestand (niet als map) |
-d pad | Bestaat als map |
-e pad | Bestaat (bestand of map) |
-r bestand | Bestaat en is leesbaar |
-w bestand | Bestaat en is beschrijfbaar |
-x bestand | Bestaat en is uitvoerbaar |
Stringvergelijking — vergelijk stukken tekst:
| Operator | Betekenis |
|---|---|
-z "$var" | String is leeg (zero length) |
-n "$var" | String is niet leeg |
"$a" = "$b" | Strings zijn gelijk |
"$a" != "$b" | Strings zijn ongelijk |
Getalvergelijking — vergelijk getallen:
| Operator | Betekenis |
|---|---|
$a -eq $b | Gelijk aan (equal) |
$a -ne $b | Niet gelijk aan (not equal) |
$a -lt $b | Kleiner dan (less than) |
$a -gt $b | Groter dan (greater than) |
$a -le $b | Kleiner of gelijk (less or equal) |
$a -ge $b | Groter of gelijk (greater or equal) |
Logisch combineren:
if [ -f bestand.txt ] && [ -r bestand.txt ]; then # Beide waar (AND)
echo "Bestand bestaat en is leesbaar"
fi
if [ -f a.txt ] || [ -f b.txt ]; then # Minstens één waar (OR)
echo "Minstens één van de bestanden bestaat"
fi
Voorbeeld — controleer een argument
#!/bin/bash
bestand=$1
if [ -z "$bestand" ]; then
echo "Gebruik: $0 <bestandsnaam>"
exit 1
fi
if [ -f "$bestand" ]; then
echo "Bestand gevonden: $bestand"
wc -l "$bestand"
else
echo "Bestand niet gevonden: $bestand"
exit 1
fi
Loops
Loops herhalen een blok code voor elk element in een lijst, of zolang een voorwaarde geldig is. Ze zijn onmisbaar voor het verwerken van meerdere bestanden of het uitvoeren van een taak een vast aantal keren.
for — itereren over een lijst
De for-loop doorloopt één voor één elk element in een lijst. Bij bestanden kun je wildcards gebruiken.
# Elk .txt bestand in de huidige map verwerken
for bestand in *.txt; do
echo "Verwerk: $bestand"
wc -l "$bestand"
done
# Over een expliciete lijst
for omgeving in dev staging prod; do
echo "Deploy naar $omgeving..."
done
# Een numerieke reeks
for i in {1..5}; do
echo "Stap $i van 5"
done
while — herhalen zolang de conditie geldt
De while-loop is handig om een bestand regel voor regel te lezen, of te wachten tot een bepaalde toestand verandert.
# Elke regel van een bestand verwerken
while read regel; do
echo "Verwerk: $regel"
done < bestand.txt
# Teller bijhouden
teller=0
while [ $teller -lt 5 ]; do
echo "Teller staat op $teller"
teller=$((teller + 1))
done
De $((... )) syntax gebruik je voor rekenkundige bewerkingen in bash.
Functies
Functies groeperen herbruikbare commando's onder een naam. Je roept ze aan als gewone commando's. Ze zijn ideaal als je hetzelfde blok meerdere keren nodig hebt — je schrijft de logica één keer en roept hem op waar nodig.
groet() {
local naam=$1 # 'local' beperkt de variabele tot deze functie
echo "Hallo, $naam!"
}
groet "Jan" # Output: Hallo, Jan!
groet "Marie" # Output: Hallo, Marie!
Functies kunnen ook een return-waarde teruggeven via de exit code (0 = succes, niet-nul = fout):
bestand_bestaat() {
if [ -f "$1" ]; then
return 0 # Succes (true)
else
return 1 # Fout (false)
fi
}
if bestand_bestaat "data.csv"; then
echo "Bestand gevonden, verwerking starten..."
else
echo "Bestand niet gevonden."
exit 1
fi
Foutafhandeling
Exit codes
Elk commando geeft na afloop een exit code terug: 0 betekent succes, alles anders betekent een fout. Je scripts kunnen dit ook gebruiken om aan te geven of ze gelukt zijn.
ls bestand.txt
echo "Exit code: $?" # $? bevat de exit code van het laatste commando
exit 0 # Script met succes beëindigen
exit 1 # Script met een fout beëindigen
set -e — automatisch stoppen bij fouten
Zonder extra configuratie gaat bash gewoon door na een fout — ook als een tussenstap mislukt is. Dat kan leiden tot onverwacht gedrag. set -e (exit on error) stopt het script zodra een commando faalt.
#!/bin/bash
set -e
mkdir backup
cp data.csv backup/ # Als dit mislukt, stopt het script hier
gzip backup/data.csv
echo "Back-up geslaagd" # Dit wordt nooit uitgevoerd als cp mislukt
Zonder set -e zou het script doorgaan na een mislukte cp en proberen een niet-bestaand bestand te comprimeren. Met set -e stopt het netjes op de fout.
Praktisch voorbeeld: back-up script
Dit script combineert alles: argumenten, condities, functies en archieven.
#!/bin/bash
set -e
# Gebruik: ./backup.sh <bronmap> <doelmap>
BRON=$1
DOEL=$2
DATUM=$(date +%Y-%m-%d)
ARCHIEF="$DOEL/backup-$DATUM.tar.gz"
controleer_argumenten() {
if [ -z "$BRON" ] || [ -z "$DOEL" ]; then
echo "Gebruik: $0 <bronmap> <doelmap>"
exit 1
fi
if [ ! -d "$BRON" ]; then
echo "Fout: bronmap '$BRON' bestaat niet."
exit 1
fi
}
maak_back_up() {
mkdir -p "$DOEL"
tar -czf "$ARCHIEF" "$BRON"
echo "Back-up aangemaakt: $ARCHIEF"
}
controleer_argumenten
maak_back_up
chmod +x backup.sh
./backup.sh projecten/ /mnt/backup/