Ich versuche, ein Skript zu erstellen, das einen auszuführenden Befehl als Zeichenfolge speichern muss. Die betreffende Zeichenfolge muss Anführungszeichen enthalten, und beim Versuch, sie auszuführen, fügt Bash zusätzliche Anführungszeichen hinzu, was in einigen Fällen dazu führt, dass der Befehl nicht wie erwartet ausgeführt wird.
Hier ist ein Beispielskript. Der example
in diesem Beispielskript ausgeführte Befehl tut offensichtlich nichts und gibt lediglich aus command not found
, Sie können das Skript jedoch trotzdem ausführen und sehen, wovon ich spreche, da ich -x
die #!/bin/bash
Zeile so ergänzt habe, dass der genaue ausgeführte Befehl ausgedruckt wird.
Beispiel:
#!/bin/bash -x
#command typed explicitly
example -options "-i filename"
#command stored in string first
commandstring='example -options "-i filename"'
echo "running command: ${commandstring}"
${commandstring}
Die Ausgabe beim Ausführen dieses Skripts ist für mich (unter Ignorierung der beiden „Befehl nicht gefunden“-Fehler):
+ example -options '-i filename'
+ commandstring='example -options "-i filename"'
+ echo 'running command: example -options "-i filename"'
running command: example -options "-i filename"
+ example -options '"-i' 'filename"'
Sie können also sehen, dass die erste Zeile natürlich wie erwartet ausgeführt wird, wenn der Befehlszeilenparameter angegeben wird:
-i filename
Obwohl der echo
Befehl die Zeichenfolge auf eine Weise druckt, die auch perfekt ausgeführt werden würde, ändert sich die Zeichenfolge, wenn sie in die Befehlszeile eingefügt wird, und der übergebene Parameter wird
'"-i' 'Dateiname"'
das zusätzliche Anführungszeichen enthält, und dies führt dazu, dass der eigentliche Befehl, den ich in meinem echten Skript verwende, fehlschlägt.
Gibt es eine Möglichkeit, dies zu verhindern?
Antwort1
Wenn Sie verwenden bash
, ist es am einfachsten, einen Befehl exakt zu speichern, indem Sie ihn in ein Array einfügen. Wenn der Befehl, den Sie ausführen möchten, lautet:
example -options "-i filename"
Sie können es in einer Array-Variable speichern mit:
commandline=(example -options "-i filename")
Anschließend können Sie den gespeicherten Befehl genauso ausführen, indem Sie das Array in Anführungszeichen mit @ erweitern:
"${commandline[@]}"
Das Wichtigste, was Sie hier wissen müssen, ist, dass die Shell Anführungszeichen ( "'\
) anders behandelt, wenn sie direkt in die Befehlszeile eingegeben werden, als wenn sie sie in einer Variablenerweiterung wie in Ihrer findet ${commandstring}
. In der Befehlszeile haben Anführungszeichen eine spezielle Anführungszeichenfunktion. In einer Parametererweiterung sind sie ganz normale, nicht spezielle Zeichen. Daher "-i filename"
ist ein einzelnes Wort, wenn es in die Befehlszeile eingegeben wird, das als analysiert wird -i filename
, aber dieselben Zeichen in einer Variablen werden zu den Wörtern "-i
und erweitert filename"
.
BashFAQ 50behandelt dieses Thema viel ausführlicher.