In meiner Bash-Umgebung verwende ich Variablen, die Leerzeichen enthalten, und diese Variablen bei der Befehlssubstitution. Leider kann ich die Antwort auf SE nicht finden.
Wie zitiere ich meine Variablen richtig? Und wie soll ich es machen, wenn diese verschachtelt sind?
DIRNAME=$(dirname "$FILE")
oder zitiere ich außerhalb der Vertretung?
DIRNAME="$(dirname $FILE)"
oder beides?
DIRNAME="$(dirname "$FILE")"
oder benutze ich back-ticks?
DIRNAME=`dirname "$FILE"`
Was ist der richtige Weg, um dies zu tun? Und wie kann ich leicht überprüfen, ob die Anführungszeichen richtig eingestellt sind?
bash
shell
quoting
command-substitution
CousinCocaine
quelle
quelle
Antworten:
In der Reihenfolge vom schlechtesten zum besten:
DIRNAME="$(dirname $FILE)"
wird nicht tun, was Sie wollen, wenn$FILE
Whitespace- oder Globbing-Zeichen enthalten\[?*
.DIRNAME=`dirname "$FILE"`
ist technisch korrekt, aber Backticks werden für die Befehlserweiterung aufgrund der zusätzlichen Komplexität beim Verschachteln nicht empfohlen .DIRNAME=$(dirname "$FILE")
ist richtig, aber nur, weil dies eine Aufgabe ist . Wenn Sie die Befehlssubstitution in einem anderen Kontext verwenden, z. B.export DIRNAME=$(dirname "$FILE")
oderdu $(dirname "$FILE")
, kann das Fehlen von Anführungszeichen zu Problemen führen, wenn das Ergebnis der Erweiterung Leerzeichen oder glühende Zeichen enthält.DIRNAME="$(dirname "$FILE")"
ist der empfohlene Weg. Sie können durchDIRNAME=
einen Befehl und ein Leerzeichen ersetzen, ohne etwas anderes zu ändern, unddirname
erhalten die richtige Zeichenfolge.Um noch weiter zu verbessern:
DIRNAME="$(dirname -- "$FILE")"
funktioniert, wenn$FILE
mit einem Bindestrich begonnen wird.DIRNAME="$(dirname -- "$FILE"; printf x)" && DIRNAME="${DIRNAME%?x}"
Funktioniert auch, wenn$FILE
mit einem Zeilenumbruch geendet wird, da$()
Zeilenumbrüche am Ende der Ausgabedirname
abgeschnitten und nach dem Ergebnis ein Zeilenumbruch ausgegeben werden . Meine Gütedirname
, warum musst du anders sein?Sie können Befehlserweiterungen beliebig verschachteln. Wenn
$()
Sie immer einen neuen Angebotskontext erstellen, können Sie Folgendes tun:Sie wollen das nicht mit Backticks versuchen.
quelle
$()
Ihnen erstellen Sie immer einen neuen Angebotskontext" , so ist es genau wie außerhalb der äußeren Anführungszeichen. Soweit ich weiß, steckt nichts mehr dahinter.Sie können die Auswirkungen der variablen Anführungszeichen immer mit anzeigen
printf
.Wortteilung durchgeführt am
var1
:var1
zitiert, also keine Wortteilung:Wortteilung nach
var1
innen$()
, entsprechendecho "hello" "world"
:Keine Wortspaltung
var1
, kein Problem, wenn man Folgendes nicht zitiert$()
:Das Wort spaltet sich
var1
wieder auf:Beides zu zitieren, ist der einfachste Weg, sicher zu sein.
Globbing-Problem
Wenn eine Variable nicht in Anführungszeichen gesetzt wird, kann dies auch zu einer globalen Erweiterung ihres Inhalts führen:
Beachten Sie, dass dies nur geschieht, nachdem die Variable erweitert wurde. Es ist nicht erforderlich, während der Zuweisung einen Glob anzugeben:
Verwenden Sie
set -f
, um dieses Verhalten zu deaktivieren:Und
set +f
um es wieder zu aktivieren:quelle
var1='hello * world'
, um auch das Problem des Globbing zu veranschaulichen.Ergänzung zur akzeptierten Antwort:
Obwohl ich der Antwort von @ l0b0 hier im Allgemeinen zustimme , vermute ich, dass die Platzierung von Backticks in der "worst to best" -Liste zumindest teilweise auf die Annahme zurückzuführen
$(...)
ist, die überall verfügbar ist. Mir ist klar, dass die Frage Bash spezifiziert, aber es gibt viele Male, in denen sich herausstellt, dass Bash/bin/sh
nicht immer die vollständige Bourne Again-Shell ist.Insbesondere weiß die Ebene Bourne - Shell nicht , was damit zu tun
$(...)
, so Skripte , die mit ihm kompatibel seinem Anspruch (zB über eine#!/bin/sh
Shebang - Zeile) wird wahrscheinlich schlecht benehmen , wenn sie von den „realen“ tatsächlich ausgeführt werden/bin/sh
- dies ist von Spezielles Interesse, wenn beispielsweise Init-Skripte erstellt oder Pre- und Post-Skripte gepackt werden und diese bei der Installation eines Basissystems an einem überraschenden Ort landen können.Wenn dies nach etwas klingt, das Sie mit dieser Variablen planen, ist das Verschachteln wahrscheinlich weniger problematisch, als wenn das Skript tatsächlich vorhersehbar ausgeführt wird. Wenn es sich um einen einfachen Fall handelt und die Portabilität ein Problem darstellt, neige ich häufig dazu, Backticks mit mehreren Zuweisungen zu verwenden, anstatt sie zu verschachteln , auch wenn ich davon ausgehe, dass das Skript normalerweise auf Systemen mit
/bin/sh
Bash ausgeführt wird.Angesichts der Allgegenwart der implementierten Shells
$(...)
(Bash, Dash, et al.) Sind wir in der Lage, uns an die hübschere, einfacher zu verschachtelnde und in jüngerer Zeit bevorzugte POSIX-Syntax zu halten, z Alle Gründe, die @ l0b0 anführt.Übrigens: Dies hat sich auch bei StackOverflow gelegentlich gezeigt -
quelle