Dit artikel legt uit waarom het gebruik van de tilde (~) in aanhalingstekens bij het definiëren van de PATH-omgevingsvariabele in Bash of Zsh problematisch is. Omdat tilde-expansie niet plaatsvindt binnen quotes, wordt de tilde niet omgezet naar het home-pad, maar behandeld als een letterlijk teken. Dit kan ertoe leiden dat de shell zoekt naar een directory genaamd ~ in de huidige werkmap.
De belangrijkste punten zijn:
- Het probleem:
export PATH="$PATH:~/.local/bin/" werkt niet zoals verwacht.
- De oplossing: Gebruik de variabele
$HOME in plaats van de tilde: export PATH="$PATH:$HOME/.local/bin/".
- Controle: Gebruik het commando
echo "$PATH" | grep -- '~' om te controleren of er onjuiste tildes in de huidige configuratie staan.
De tilde in je PATH is mogelijk niet je HOME
In andere woorden: wanneer je het volgende in je ~/.bashrc of ~/.zshrc zet:
export PATH="$PATH:~/.local/bin/"
dan zal de ~ (tilde) niet worden uitgebreid naar het home-pad (of $HOME). Tilde-expansie vindt namelijk alleen plaats bij invoer die niet tussen aanhalingstekens staat, zoals de Bash-documentatie stelt:
"Als een woord begint met een ongequoteerd tilde-teken (‘~’), worden alle tekens tot de eerste ongequoteerde slash (…) beschouwd als een tilde-prefix. (…) Bash controleert elke variabeletoewijzing op ongequoteerde tilde-prefixes die direct volgen op een ‘:’ of de eerste ‘=’, en voert in deze gevallen tilde-expansie uit. (...)"
In plaats van dat /home/<gebruiker>/.local/bin/ aan de PATH wordt toegevoegd, eindigen we dus met ./~/.local/bin/ in de PATH.
De oplossing
Om dit te herstellen, kun je het volgende doen:
export PATH="$PATH:$HOME/.local/bin/"
Let op dat de ongequoteerde versie export PATH=$PATH:~/.local/bin overigens wel werkt in Bash en Zsh, omdat tilde-expansie ook wordt uitgevoerd bij variabeletoewijzingen na = en na elke :. Het is echter riskant om hierop te vertrouwen; zo kan een spatie bijvoorbeeld de variabeletoewijzing verbreken.
Demonstratie van het probleem
Het probleem is hier duidelijk te zien:
$ ls -la
total 0
drwxr-xr-x@ 2 dc staff 64 Oct 2 13:37 .
drwxr-x---+ 105 dc staff 3360 Oct 2 13:37 ..
$ mkdir -p ./~/.local/bin/
$ printf '#include <stdio.h>\nint main() { puts("hello"); }'>a.c; gcc a.c -o ./~/.local/bin/kek
$ PATH="~/.local/bin/" kek
hello
$ tree -f
.
├── ./~
│ └── ./~/.local
│ └── ./~/.local/bin
│ └── ./~/.local/bin/kek
└── ./a.c
4 directories, 2 files
Zoals we kunnen zien, werd het kek-binary bestand gevonden en uitgevoerd vanuit ./~/.local/bin/ — de home-directory was hier nooit bij betrokken.
Controleer je PATH
Je kunt snel controleren of je dit probleem hebt met het volgende commando:
$ echo "$PATH" | grep -- '~'
Of, om elke entry op een eigen regel te zien:
$ echo "$PATH" | tr ':' '\n' | grep '~'
~/.local/bin/
Als dit iets print, pas dan je .bashrc, .zshrc of .profile aan en vervang de ~ door $HOME.
Terloops: complimenten aan de nono-tool voor de waarschuwing, ook al had deze uitgebreider kunnen zijn.
De tilde in je PATH is mogelijk niet je HOME
In andere woorden: wanneer je het volgende in je ~/.bashrc of ~/.zshrc zet:
export PATH="$PATH:~/.local/bin/"
dan zal de ~ (tilde) niet worden uitgebreid naar het home-pad (of $HOME). Tilde-expansie vindt namelijk alleen plaats bij invoer die niet tussen aanhalingstekens staat, zoals de Bash-documentatie stelt:
"Als een woord begint met een ongequoteerd tilde-teken (‘~’), worden alle tekens tot de eerste ongequoteerde slash (…) beschouwd als een tilde-prefix. (…) Bash controleert elke variabeletoewijzing op ongequoteerde tilde-prefixes die direct volgen op een ‘:’ of de eerste ‘=’, en voert in deze gevallen tilde-expansie uit. (...)"
In plaats van dat /home/<gebruiker>/.local/bin/ aan de PATH wordt toegevoegd, eindigen we dus met ./~/.local/bin/ in de PATH.
De oplossing
Om dit te herstellen, kun je het volgende doen:
export PATH="$PATH:$HOME/.local/bin/"
Let op dat de ongequoteerde versie export PATH=$PATH:~/.local/bin overigens wel werkt in Bash en Zsh, omdat tilde-expansie ook wordt uitgevoerd bij variabeletoewijzingen na = en na elke :. Het is echter riskant om hierop te vertrouwen; zo kan een spatie bijvoorbeeld de variabeletoewijzing verbreken.
Demonstratie van het probleem
Het probleem is hier duidelijk te zien:
$ ls -la
total 0
drwxr-xr-x@ 2 dc staff 64 Oct 2 13:37 .
drwxr-x---+ 105 dc staff 3360 Oct 2 13:37 ..
$ mkdir -p ./~/.local/bin/
$ printf '#include <stdio.h>\nint main() { puts("hello"); }'>a.c; gcc a.c -o ./~/.local/bin/kek
$ PATH="~/.local/bin/" kek
hello
$ tree -f
.
├── ./~
│ └── ./~/.local
│ └── ./~/.local/bin
│ └── ./~/.local/bin/kek
└── ./a.c
4 directories, 2 files
Zoals we kunnen zien, werd het kek-binary bestand gevonden en uitgevoerd vanuit ./~/.local/bin/ — de home-directory was hier nooit bij betrokken.
Controleer je PATH
Je kunt snel controleren of je dit probleem hebt met het volgende commando:
$ echo "$PATH" | grep -- '~'
Of, om elke entry op een eigen regel te zien:
$ echo "$PATH" | tr ':' '\n' | grep '~'
~/.local/bin/
Als dit iets print, pas dan je .bashrc, .zshrc of .profile aan en vervang de ~ door $HOME.
Terloops: complimenten aan de nono-tool voor de waarschuwing, ook al had deze uitgebreider kunnen zijn.