In meiner Bash-Umgebung verwende ich Variablen, die Leerzeichen enthalten, und ich verwende diese Variablen innerhalb der Befehlsersetzung.
Wie zitiere ich meine Variablen richtig? Und wie soll ich das machen, wenn diese verschachtelt sind?
DIRNAME=$(dirname "$FILE")
oder zitiere ich außerhalb der Ersetzung?
DIRNAME="$(dirname $FILE)"
oder beides?
DIRNAME="$(dirname "$FILE")"
oder verwende ich Backticks?
DIRNAME=`dirname "$FILE"`
Was ist der richtige Weg, dies zu tun? Und wie kann ich einfach überprüfen, ob die Anführungszeichen richtig gesetzt sind?
Akzeptierte Antwort:
In der Reihenfolge vom Schlechtesten zum Besten:
DIRNAME="$(dirname $FILE)"
wird nicht das tun, was Sie wollen, wenn$FILE
enthält Leerzeichen (oder beliebige Zeichen$IFS
enthält derzeit) oder Globbing-Zeichen[?*
.DIRNAME=`dirname "$FILE"`
ist technisch korrekt, aber Backticks werden wegen der zusätzlichen Komplexität beim Verschachteln und der zusätzlichen Backslash-Verarbeitung, die darin stattfindet, nicht für die Befehlserweiterung empfohlen.DIRNAME=$(dirname "$FILE")
ist korrekt, aber nur, weil dies eine Zuweisung an eine skalare (nicht Array-) Variable ist. Wenn Sie die Befehlsersetzung in einem anderen Kontext verwenden, z. B.export DIRNAME=$(dirname "$FILE")
oderdu $(dirname -- "$FILE")
, führt das Fehlen von Anführungszeichen zu Problemen, wenn das Ergebnis der Erweiterung Leerzeichen oder Globbing-Zeichen enthält.DIRNAME="$(dirname "$FILE")"
(mit Ausnahme des fehlenden--
, siehe unten) ist der empfohlene Weg. Sie könnenDIRNAME=
ersetzen mit einem Befehl und einem Leerzeichen, ohne etwas anderes zu ändern, unddirname
erhält den richtigen String.
Noch weiter verbessern:
DIRNAME="$(dirname -- "$FILE")"
funktioniert wenn$FILE
beginnt mit einem Bindestrich.DIRNAME="$(dirname -- "$FILE" && printf x)" && DIRNAME="${DIRNAME%?x}" || exit
funktioniert auch wenn$FILE
Der Dirname endet mit einem Zeilenumbruch, da$()
schneidet Zeilenumbrüche am Ende der Ausgabe ab, sowohl die vondirname
hinzugefügten und diejenigen, die Teil der eigentlichen Daten sein können.
Sie können Befehlserweiterungen beliebig verschachteln. Mit $()
Sie erstellen immer einen neuen Zitierkontext, sodass Sie beispielsweise Folgendes tun können:
foo "$(bar "$(baz "$(ban "bla")")")"
Du nicht möchte das mit Backticks versuchen.