![Warum bewerten Bash und Zsh [-1] als 1?](https://rvso.com/image/1681636/Warum%20bewerten%20Bash%20und%20Zsh%20%5B-1%5D%20als%201%3F.png)
Mir ist dieses überraschende Verhalten aufgefallen und ich kann nicht ganz verstehen, was da los ist:
$ bash -c 'echo [-1]'
1
$ zsh -c 'echo [-1]'
1
Es scheint, als ob der Befehlsparser versucht, einen Ausdruck auszuwerten:
$ echo [1,2,3]
1
$ echo [123-33]
1
Denn wenn der Ausdruck in Anführungszeichen gesetzt wird, oder darauf hingewiesen wird, dass es sich bei einer Klammer nur um eine Klammer handelt, dann unterbleibt die seltsame Auswertung.
$ echo \[123-33]
[123-33]
$ echo [123-33\]
[123-33]
$ echo '[123-33]'
[123-33]
Auf der Suche nach Hinweisen stieß ich auf dieses Zitat:
Vorbehalte
Verwenden Sie beim Indizieren assoziativer Bash-Arrays immer Anführungszeichen. Andernfalls muss der statische Parser davon ausgehen, dass der Index ein arithmetischer Ausdruck ist.
$ echo '${array[spaced string]}' | shfmt 1:16: not a valid arithmetic operator: string $ echo '${array[dash-string]}' | shfmt ${array[dash - string]}
Ich bin nicht sicher, was ich davon halten soll, da es im Zusammenhang mitecho [1-1]
Dies könnte natürlich durch etwas in meiner eigenen Umgebung verursacht werden, aber wenn ich nachschaue, scheint es nicht daran zu liegen:
$ env -i HOME=$(mktemp -d) bash --noprofile --norc
bash-5.1$ echo [1-1]
1
$ env -i HOME=$(mktemp -d) /bin/bash-4.4 --noprofile --norc
bash-4.4-4.4$ echo [1-1]
1
Auf einer Ubuntu-Box erhalte ich jedoch ein anderes Ergebnis:
$ bash --version | sed 1q; echo [1-1]
GNU bash, version 5.0.17(1)-release (x86_64-pc-linux-gnu)
[1-1]
Das Deaktivieren aller Optionen ändert dieses Verhalten nicht.
for i in `shopt | awk '/on$/ { print $1}'`; do shopt -u $i;done
Haben Sie eine Idee, warum dieser Klammer-Ausdruck ausgewertet wird und warum das Ergebnis 1 ist?
Antwort1
Dies geschieht nur, wenn Sie eine Datei mit dem Namen 1
im aktuellen Verzeichnis haben.
$ bash -c 'echo [-1]'
[-1]
$ touch 1
$ bash -c 'echo [-1]'
1
$ rm 1
$ bash -c 'echo [-1]'
[-1]
Warum? Die Shell führt Globbing durch, [-1]
das mit Dateien namens -
oder übereinstimmt 1
. Wenn also eine Datei mit einem solchen einstelligen Namen existiert, stimmt der Glob überein und Sie erhalten den Dateinamen. Wenn keine solche Datei existiert, bleibt der Glob unverändert.
PS: Es funktioniert auch mit -
:
$ touch ./-
$ bash -c 'echo [-1]'
-