Tips en Trucs 2026

De read opdracht

De read opdracht is een ingebouwde functie van de Bash-shell die gebruikersinvoer vastlegt en toewijst aan variabelen, waardoor het essentieel is voor interactieve scripts. Veelvoorkomende gebruikssituaties zijn onder meer het vragen om gebruikersnamen en wachtwoorden, het regel voor regel verwerken van CSV-bestanden, het implementeren van bevestigingsdialoogvensters en het bouwen van menugestuurde interfaces. Aan het einde van deze tip ben je in staat om enkelvoudige en meervoudige invoeren vast te leggen, gevoelige gegevens veilig te verwerken, tijdslimieten te implementeren, bestanden efficiënt te verwerken en veelvoorkomende valkuilen op te lossen.

Als je nog niet bekend bent met read, kun je het zien als een pauzeknop die wacht tot iemand je script beantwoordt voordat het verdergaat. De read opdracht legt een regel invoer vast vanuit de standaardinvoer (stdin) en wijst deze toe aan één of meer variabelen. Standaard wacht read op gebruikersinvoer en slaat deze op in een variabele.

Eenvoudige gebruikersinvoer vastleggen

In de eenvoudigste vorm wacht read tot iemand een antwoord typt voordat het script verdergaat. Het volgende script bestaat uit het absolute minimum dat nodig is om één antwoord te verzamelen en onmiddellijk te reageren.

Het script read.sh maken we met de nano teksteditor aan met de volgende opdracht:

dany@pindabook:~$ nano read.sh

En bevat het volgende script:

 GNU nano 8.4                                   read.sh *                                            
#!/bin/bash
echo "Wat is uw naam?"
read user_name
echo "Hallo, $user_name!"



^G Hulp       ^O Opslaan    ^F Zoeken     ^K Knippen    ^T Opdracht   ^C Positie    M-U Terugdraaien
^X Afsluiten  ^R Inlezen    ^\ Vervangen  ^U Plakken    ^J Uitvullen  ^/ Naar regel M-E Herdoen

Sla het script op de sneltoets Ctrl+s en verlaat nano met de sneltoets Ctrl+x. Voer het script uit met:

dany@pindabook:~$ bash read.sh  
Wat is uw naam?
John
Hallo, John!

Het script bestaat uit drie stappen:

De standaardvariabele $REPLY

In het vervolg van deze tip passen we telkens het script read.sh aan met nano, zoals hierboven uitgelegd.

Wanneer je read gebruikt zonder een variabelenaam op te geven, slaat de opdracht de invoer automatisch op in de ingebouwde variabele $REPLY:

#!/bin/bash
read  
echo "Uw antwoord: $REPLY"

Voer het aangepaste script uit:

dany@pindabook:~$ bash read.sh  
Mijn invoer
Uw antwoord: Mijn invoer

Dit gedrag is handig in snelle scripts of wanneer je een consistente variabelenaam wilt gebruiken in verschillende delen van het script. Vergeet niet om REPLY te verwijderen (unset REPLY) of te overschrijven nadat je ermee klaar bent, zodat de waarde niet in latere opdrachten terechtkomt.

Meerdere invoeren vastleggen met één opdracht

Naast het vastleggen van afzonderlijke waarden kan de read opdracht meerdere invoeren opslaan door meerdere variabelenamen op te geven. Wanneer een gebruiker waarden opgeeft die door spaties zijn gescheiden, wijst read elke waarde toe aan een overeenkomstige variabele.

#!/bin/bash
echo "Geef jouw voornaam en naam in:"
read first_name last_name    
echo "Voornaam: $first_name"
echo "Naam: $last_name"

dany@pindabook:~$ bash read.sh  
Geef jouw voornaam en naam in:
John Doe
Voornaam: John
Naam: Doe

Zo werkt het:

Invoer opslaan in arrays voor dynamische gegevens

Wanneer het aantal invoervelden varieert of je meerdere waarden efficiënt moet verwerken, kun je met de optie -a de invoer rechtstreeks in een array opslaan.

#!/bin/bash
read -a colors -p "Geef jouw favoriete kleuren in: "
echo "Eerste kleur: ${colors[0]}"
echo "Tweede kleur: ${colors[1]}"
echo "Alle kleuren: ${colors[@]}"

dany@pindabook:~$ bash read.sh  
Geef jouw favoriete kleuren in: Rood Groen Blauw
Eerste kleur: Rood
Tweede kleur: Groen
Alle kleuren: Rood Groen Blauw

Hoe de optie -a arrays bouwt:

Arrays gebruiken voor servercontroles

Arrays zijn vooral handig bij het verwerken van opdracht resultaten of het bouwen van dynamische configuraties. Door een herestring (<<<) te gebruiken, blijft de array in de huidige shell item per item gelezen worden, zodat deze gevuld blijft voor de volgende lus. Als je in plaats daarvan een pipe (invoeromleiding) naar de opdracht gebruikt, wordt de lus in een subshell uitgevoerd en wordt de array verwijderd zodra de subshell wordt afgesloten. Gebruik dus een herestring of invoeromleiding wanneer je de gegevens opnieuw wilt gebruiken.

#!/bin/bash
read -a servers <<< "pindanet.be google.be debian.be"
for server in "${servers[@]}"; do
 echo "Pinging $server..."
 ping -c 1 "$server" > /dev/null 2>&1 && echo "$server is online"
done

dany@pindabook:~$ bash read.sh  
Pinging pindanet.be...
pindanet.be is online
Pinging google.be...
google.be is online
Pinging debian.be...

De laatste server (debian.be) is niet online, want deze bestaat niet.

Gegevens verwerken met herestrings

Een vereenvoudigd voorbeeld:

#!/bin/bash
read -r first last <<< "John Doe"
echo "Voornaam: $first, Naam: $last"

dany@pindabook:~$ bash read.sh  
Voornaam: John, Naam: Doe

Deze techniek is vooral handig in combinatie met opdrachtvervanging om opdracht resultaten direct te verwerken:

#!/bin/bash
IFS="@" read -r user host <<< "$(whoami)@$(hostname)"
echo "Actieve gebruiker: $user op host: $host"

dany@pindabook:~$ bash read.sh  
Actieve gebruiker: dany op host: pindabook

Door IFS in te stellen op @ voor de duur van opdracht, wordt de uitvoer netjes opgesplitst in de velden user en hostname, in plaats van de hele tekenreeks als één waarde te behandelen.

Een aangepast scheidingsteken gebruiken voor het splitsen van invoer

Standaard splitst read invoer op witruimte, zoals spaties, tabs en nieuwe regels, omdat de Internal Field Separator (IFS) deze waarden bevat. Bij gestructureerde gegevens, zoals CSV-bestanden of andere gescheiden formaten, heb je vaak een ander scheidingsteken nodig. Door IFS aan te passen, verander je hoe read tekst splitst.

De IFS-variabele bepaalt dus hoe woorden binnen een regel worden gesplitst. Door deze in te stellen op een komma vóór read, wordt de opdracht geïnstrueerd om op komma's te splitsen in plaats van op witruimte:

#!/bin/bash
IFS="," read -r name age city <<< "John Doe,30,Brugge"
echo "Naam: $name"
echo "Leeftijd: $age"
echo "Woonplaats: $city"

dany@pindabook:~$ bash read.sh  
Naam: John Doe
Leeftijd: 30
Woonplaats: Brugge

Hoe IFS=”,” CSV-velden splitst:

CSV-velden uit een bestand verwerken

Een meer praktische implementatie zou zijn om een CSV-bestand regel voor regel te verwerken.

Om dit te demonstreren, maken we een CSV-bestand met nano aan:

dany@pindabook:~$ nano users.csv

Met de volgende CSV-regels:

John Doe,30,Brugge
Clara Doe,29,Blankenberge
Stefaan Doe,24,Gent

Het volgende script verwerkt gestructureerde gegevens in het pas aangemaakte CSV-bestand op efficiënte wijze, waardoor het nuttig is voor gegevensmigratie, rapportage en automatisering.

#!/bin/bash
while IFS="," read -r name age city; do
 echo "Naam: $name, Leeftijd: $age, Woonplaats: $city"
done < users.csv

dany@pindabook:~$ bash read.sh  
Naam: John Doe, Leeftijd: 30, Woonplaats: Brugge
Naam: Clara Doe, Leeftijd: 29, Woonplaats: Blankenberge
Naam: Stefaan Doe, Leeftijd: 24, Woonplaats: Gent

Regeleinde

Terwijl IFS bepaalt hoe woorden binnen een regel worden gesplitst, verandert de -d optie wat het einde van een regel markeert. Standaard stopt read bij een nieuwe regel, maar je kunt een ander teken specificeren:

#!/bin/bash
read -d ";" data <<< "status=ready;pending"
echo "Lees tot aan de puntkomma: $data"

dany@pindabook:~$ bash read.sh  
Lees tot aan de puntkomma: status=ready

Dit is handig bij het verwerken van gegevens die niet-standaard regeleinden gebruiken, zoals Windows-geformatteerde bestanden of aangepaste gegevensstromen. De herestring houdt de tekenreeks vast en de opdracht gebruikt de puntkomma als scheidingsteken, zodat deze niet wordt opgenomen in de opgeslagen waarde.

#!/bin/bash
read -s -p "Voer uw wachtwoord in: " password
printf "\nWachtwoord ontvangen.\n"

dany@pindabook:~$ bash read.sh  
Voer uw wachtwoord in:  
Wachtwoord ontvangen.

Veilige wachtwoordinvoer

Bij het verwerken van gevoelige gegevens zoals wachtwoorden of API-sleutels is het niet wenselijk om gebruikersinvoer op de terminal weer te geven. De -s optie zorgt ervoor dat de invoer verborgen blijft.

#!/bin/bash
read -s -p "Voer de MySQL gebruiker in: " mysql_user
printf "\n"
read -s -p "Voer het MySQL wachtwoord in: " mysql_pass
printf "\n"
mysql --defaults-extra-file=<(printf "[client]\nuser=%s\npassword=%s\n" "$mysql_user"  "$mysql_pass") -e "SHOW DATABASES;"
unset mysql_user
unset mysql_pass

dany@pindabook:~$ bash read.sh  
Voer de MySQL gebruiker in:  
Voer het MySQL wachtwoord in:  
+--------------------+
| Database           |
+--------------------+
| information_schema |
| pindanet_db        |
+--------------------+

Afgeschermde wachtwoordinvoer:

Door een tijdelijk bestand met clientgegevens te gebruiken, blijft het wachtwoord buiten de proceslijst. Wis de variabele daarna altijd om de blootstelling in het geheugen te verminderen.

Eén teken invoeren

Voor eenvoudige ja/nee-bevestigingen of menuselecties is het efficiënter om één enkel teken te lezen dan te wachten op volledige tekstinvoer. De -n optie beperkt het aantal vastgelegde tekens.

#!/bin/bash
read -n 1 -p "Druk op J om door te gaan: " key
printf "\nJe hebt het volgende ingedrukt: %s\n" "$key"

dany@pindabook:~$ bash read.sh  
Druk op J om door te gaan: n
Je hebt het volgende ingedrukt: n

Eén teken invoeren:

Scripts die snelle bevestigingen vereisen, gebruiken deze methode:

#!/bin/bash
read -n 1 -p "Nu opnieuw opstarten? (J/N): " confirm
printf "\n"
[[ $confirm == [Jj] ]] && sudo systemctl reboot

dany@pindabook:~$ bash read.sh  
Nu opnieuw opstarten? (J/N): n
dany@pindabook:~$ bash read.sh  
Nu opnieuw opstarten? (J/N): j
[sudo] wachtwoord voor dany:  
sudo: een wachtwoord is verplicht

Je kunt het uitvoeren van een herstart (en een script) afbreken met de sneltoets Ctrl+c. Deze techniek verbetert de gebruikerservaring door onnodige toetsaanslagen te verminderen.

Precies N tekens lezen met -N

De -N optie (hoofdletters) leest precies het opgegeven aantal tekens en negeert alle scheidingstekens, inclusief nieuwe regels:

#!/bin/bash
read -N 6 -p "Voer de PIN-code (precies 6 tekens) in: " code
printf "\nIngevoerde code: %s\n" "$code"

dany@pindabook:~$ bash read.sh  
Voer de PIN-code (precies 6 tekens) in: aqwzsx
Ingevoerde code: aqwzsx

In tegenstelling tot -n wordt de opdracht bij gebruik van -N niet beëindigd door op Enter te drukken. De opdracht wacht tot je precies zes tekens hebt ingevoerd. Dit is handig voor codes met een vaste lengte, pincodes of het valideren van opgemaakte invoer.

Een tijdslimiet instellen

In geautomatiseerde of onbemande omgevingen zijn er scenario's waarin een script moet doorgaan als de gebruiker niet binnen een bepaalde tijd invoer ingeeft. Met de -t optie kan een time-out worden ingesteld om te voorkomen dat er oneindig lang wordt gewacht.

#!/bin/bash
echo "1 Opslaan en afsluiten."
echo "2 Niet opslaan en afsluiten."
echo "3 Verder werken."
read -t 5 -n 1 -p "Voer uw keuze in (standaard is ‘Verder werken’): " choice
printf "\n"
choice=${choice:-"3"}
echo "Uw keuze: $choice"

dany@pindabook:~$ bash read.sh  
1 Opslaan en afsluiten.
2 Niet opslaan en afsluiten.
3 Verder werken.
Voer uw keuze in (standaard is ‘Verder werken’): 1
Uw keuze: 1
dany@pindabook:~$ bash read.sh  
1 Opslaan en afsluiten.
2 Niet opslaan en afsluiten.
3 Verder werken.
Voer uw keuze in (standaard is ‘Verder werken’):  
Uw keuze: 3

Wat gebeurt er?

Bij onbemande (automatische) scripts gebruiken vaak tijdslimieten:

#!/bin/bash
echo -n "Druk op een willekeurige toets om door te gaan, of wacht 5 seconden... "
read -t 5 -n 1 key || printf "\nTijdslimiet verstreken, doorgaan..."
printf "\n"

dany@pindabook:~$ bash read.sh  
Druk op een willekeurige toets om door te gaan, of wacht 5 seconden... d
dany@pindabook:~$ bash read.sh  
Druk op een willekeurige toets om door te gaan, of wacht 5 seconden...  
Tijdslimiet verstreken, doorgaan...

Retourcodes en foutafhandeling

De read opdracht retourneert verschillende exitcodes, afhankelijk van of de bewerking slaagt of mislukt. Een goede foutafhandeling zorgt ervoor dat scripts in alle scenario's correct werken.

#!/bin/bash
echo "1 Opslaan en afsluiten."
echo "2 Niet opslaan en afsluiten."
echo "3 Verder werken."
if read -t 5 -p "Voer uw keuze in: " choice; then
 echo "U hebt gekozen voor: $choice"
else
 echo "Geen invoer ontvangen of tijdslimiet overschreden."
fi

dany@pindabook:~$ bash read.sh  
1 Opslaan en afsluiten.
2 Niet opslaan en afsluiten.
3 Verder werken.
Voer uw keuze in: 1
U hebt gekozen voor: 1
dany@pindabook:~$ bash read.sh  
1 Opslaan en afsluiten.
2 Niet opslaan en afsluiten.
3 Verder werken.
Voer uw keuze in: Geen invoer ontvangen of tijdslimiet overschreden.

Exit waarden:

Deze structuur is essentieel voor het bouwen van robuuste scripts die op een elegante manier omgaan met gebruikersinteractie, vooral in combinatie met time-outs of bij het lezen van pipes die onverwachts kunnen worden gesloten.

Invoer uit een bestand lezen

Naast interactieve gebruikersinvoer gebruiken scripters vaak de read opdracht in een lus om bestanden regel voor regel te verwerken. Deze aanpak is essentieel voor automatiseringstaken waarbij configuratiebestanden moeten worden geanalyseerd, logbestanden moeten worden verwerkt of batchgegevens moeten worden afgehandeld.

#!/bin/bash
while IFS= read -r line; do
 echo "Verwerken van: $line"
done < users.csv

dany@pindabook:~$ bash read.sh  
Verwerken van: John Doe,30,Brugge
Verwerken van: Clara Doe,29,Blankenberge
Verwerken van: Stefaan Doe,24,Gent

De werking van de lus:

Logs controleren op foutmeldingen

Het automatiseren van logbestandsverwerking is een ander praktisch scenario waarin read van onschatbare waarde blijkt te zijn. De onderstaande lus volgt de logboek vermeldingen van de journalctrl opdracht continu, zodat nieuwe vermeldingen jouw automatisering onmiddellijk activeren:

#!/bin/bash
while IFS= read -r log_entry; do
 echo "Zoeken in: $log_entry"
 [[ $log_entry == *"ERROR"* ]] && echo "Waarschuwing: Er is een fout gevonden!"
done < <(sudo journalctl -fqn0)

dany@pindabook:~$ bash read.sh  
[sudo] wachtwoord voor dany:  
^C

Daar dit script blijft luisteren naar gegevens van de journalctl opdracht, moet je dit script afbreken met de Ctrl+c sneltoets.

Door een lege IFS-waarde en de -r optie te gebruiken, blijft elke logboekvermelding precies zoals geschreven, terwijl procesvervanging de lus blijft voeden. Om de logboekanalyse verder te verfijnen, kun je read combineren met de grep opdracht om specifieke patronen te filteren voordat elke regel wordt verwerkt.

Veelvoorkomende problemen oplossen

Zelfs ervaren gebruikers ondervinden soms problemen bij het werken met de read opdracht. In de volgende paragrafen worden enkele problemen met foutmeldingen en oplossingen behandeld.

Illegale opties in niet-Bash-shells

#!/bin/bash
read -t 10 -s -p "Voer uw wachtwoord in: " password
printf "\nWachtwoord ontvangen.\n"

Als je bovenstaande script uitvoert met bash of dash krijg je het volgende:

dany@pindabook:~$ bash read.sh  
Voer uw wachtwoord in:  
Wachtwoord ontvangen.
dany@pindabook:~$ dash read.sh  
read.sh: 2: read: Illegal option -t

Wachtwoord ontvangen.

Het script wordt uitgevoerd in een POSIX-shell die geen Bash-specifieke opties ondersteunt. Los dit op door ervoor te zorgen dat het script met Bash wordt uitgevoerd (eerste regel). Je kunt ook controleren welke shell je script uitvoert (laatste regel).

#!/bin/bash
# Gebruik /bin/bash, niet /bin/sh, voor Bash-functies
echo $0
echo $BASH_VERSION

Scripts worden met de chmod opdracht bijna altijd uitvoerbaar gemaakt. Daardoor kan je een script starten in de standaard shell (vb: bash). Met de #!/bin/bash als eerste regel bepaal je zelf waarmee het script wordt uitgevoerd.

dany@pindabook:~$ chmod +x read.sh  
dany@pindabook:~$ ./read.sh  
./read.sh
5.2.37(1)-release
dany@pindabook:~$ bash read.sh  
read.sh
5.2.37(1)-release
dany@pindabook:~$ dash read.sh  
read.sh

Als de variabele $BASH_VERSION leeg is, wordt Bash niet gebruikt.

Variabele leeg na piping naar read

Een veelgemaakte fout is het doorsturen (pipen) van gegevens naar read en vervolgens ontdekken dat de variabele leeg is:

#!/bin/bash
# Dit werkt NIET zoals verwacht.
echo "Hallo" | read myvar
echo "Waarde: $myvar"
# Correct: gebruik herestring.
read myvar <<< "Hallo"
echo "Waarde: $myvar"  

dany@pindabook:~$ bash read.sh  
Waarde:  
Waarde: Hallo

De variabele in het eerste deel is leeg omdat de pipe een subshell voor de read opdracht aanmaakt en de variabele wordt verwijderd wanneer de subshell wordt afgesloten. In het tweede deel corrigeren we dit door een herestring of procesvervanging te gebruiken.

Onverwacht gedrag met witruimte

Als voor- of achterliggende spaties uit de invoer verdwijnen, worden ze verwijderd door de standaard IFS-waarde (spatie, tab, nieuwe regel). Stel IFS in op een lege waarde en gebruik de -r optie om de oorspronkelijke invoer te behouden:

#!/bin/bash
# Zonder IFS= worden voorloopspaties verwijderd.
read line <<< "   Hallo wereld   "
echo "[$line]"
# Met IFS= blijven witruimtes behouden.
IFS= read -r line <<< "   Hallo wereld   "
echo "[$line]"

dany@pindabook:~$ bash read.sh  
[Hallo wereld]
[   Hallo wereld   ]

Wanneer je later de variabele gebruikt, zet je deze altijd tussen dubbele aanhalingstekens (bijvoorbeeld "$line") om woordafbreking te voorkomen en de exacte inhoud te behouden.

Backslashes verdwijnen

Zonder de -r optie interpreteert read backslashes (\) als escape-tekens:

#!/bin/bash
# Zonder -r worden backslashes geïnterpreteerd.
read path <<< "C:\Users\test"
echo "$path"
# Met -r blijven backslashes behouden.
read -r path <<< "C:\Users\test"
echo "$path"

dany@pindabook:~$ bash read.sh  
C:Userstest
C:\Users\test

Gebruik altijd -r, tenzij je specifiek backslash-interpretatie nodig hebt.

Lezen in een lus verbruikt stdin

Wanneer je read gebruikt in een while-lus die ook leest vanuit stdin, kan de lus onverwacht worden afgesloten of invoer verwerken die bedoeld is voor de gebruiker (toetsenbord invoer). Gebruik een andere bestandsdescriptor om bestandsinvoer te scheiden van gebruikersinvoer:

#!/bin/bash
# Lees bestand op fd 3, houd stdin vrij voor gebruikersinvoer.
while IFS= read -r line <&3; do
 echo "Verwerken: $line"
 read -n 1 -p "Doorgaan? (j/n): " answer
 printf "\n"
 [[ $answer != "j" ]] && break
done 3< users.csv

dany@pindabook:~$ bash read.sh  
Verwerken: John Doe,30,Brugge
Doorgaan? (j/n): j
Verwerken: Clara Doe,29,Blankenberge
Doorgaan? (j/n): n

Deze techniek bewaart bestandsgegevens op bestanddescriptor 3, terwijl stdin beschikbaar blijft voor interactieve toetsenbord invoer.

read

Opruimen

Dit is vandaag eenvoudig. Enkel de twee aangemaakte bestanden verwijderen en klaar:

dany@pindabook:~$ rm read.sh users.csv