Aufruf von Bash von sh (Bindestrich) mit aus Argumenten gelesenen Befehlen und „Nicht abgeschlossener zitierter String“/„unerwartetes EOF“

Aufruf von Bash von sh (Bindestrich) mit aus Argumenten gelesenen Befehlen und „Nicht abgeschlossener zitierter String“/„unerwartetes EOF“

Ich dachte nur, ich dokumentiere das: Ich versuche etwas ganz Einfaches – setze die Umgebungsvariable in bashund drucke sie aus:

$ bash -c "a=1; echo a$a;"
a
$ bash -c "a=1; echo a\$a;"
a1

Jetzt möchte ich dasselbe, aber mit dem Argument von ( ergibt shauf meinem System ):ls -la $(which sh)/bin/sh -> dash

$ sh -c "bash -c "a=1; echo a\$a;""
a$a

# obviously I have to escape inner quotes:

$ sh -c "bash -c \"a=1; echo a\$a;\""
a

# escape the dollar once more?

$ sh -c "bash -c \"a=1; echo a\\$a\" "
sh: Syntax error: Unterminated quoted string

# nope... inner single quotes, then?

$ sh -c "bash -c 'a=1; echo a$a;'"
a

# nope... escape the single quotes?

$ sh -c "bash -c \'a=1; echo a$a;\'"
bash: -c: line 0: unexpected EOF while looking for matching `''
bash: -c: line 1: syntax error: unexpected end of file
a
sh: ': not found

# nope... escape the dollar too?

$ sh -c "bash -c \'a=1; echo a\$a;\'"
bash: -c: line 0: unexpected EOF while looking for matching `''
bash: -c: line 1: syntax error: unexpected end of file
a
sh: ': not found

Meine Frage wäre also: Was ist die richtige Syntax zum Escapen, sodass sh -c [bash -c ...]dasselbe Ergebnis wie einfach erhalten wird bash -c ...?

Antwort1

In einfachen Anführungszeichen hat kein Zeichen eine besondere Bedeutung. In doppelten Anführungszeichen "\$`haben sie eine besondere Bedeutung. Arbeiten Sie es von außen nach innen aus: Finden Sie zuerst heraus, welche Zeichenfolge von der äußeren Schale gebildet wird, und dann, was die innere Schale daraus macht.

Angenommen, die Variable aist nicht in der äußeren Hülle definiert, mit

sh -c "bash -c \"a=1; echo a\$a;\""

die äußere Shell erkennt einen in Anführungszeichen gesetzten String, der zu erweitert wird bash -c "a=1; echo a$a;", und dieser String wird an das Zwischenelement übergeben sh. shanalysiert dies als einen Aufruf von bashmit den beiden Argumenten -cund a=1; echo a;, wobei letzteres aus der Erweiterung des in Anführungszeichen gesetzten Strings resultiert, "a=1; echo a$a;"in dem die Variable anicht definiert ist.

Wenn Sie diese Analyse durchführen, können Sie sehen, dass eine Möglichkeit, das gewünschte Ergebnis zu erzielen, darin besteht, "a=1; echo a\$a;"in dieser Phase Folgendes zu haben. Um diesen zusätzlichen Backslash zu erhalten, müssen Sie im Original zwei Backslashs einfügen, da bereits eine Phase der Shell-Erweiterung in doppelten Anführungszeichen erfolgt ist. Zwei plus eins ist drei.

sh -c "bash -c \"a=1; echo a\\\$a;\""

Es wäre einfacher, einfache Anführungszeichen für die äußere Zeichenfolge zu verwenden, da Sie dort nichts erweitern möchten.

sh -c 'bash -c "a=1; echo a\$a;"'

bashDa Sie beim Aufruf von einem der beiden nichts erweitern möchten sh, können Sie auch hier einfache Anführungszeichen verwenden. Sie können keine einfachen Anführungszeichen in eine Zeichenfolge in einfachen Anführungszeichen setzen, aber es gibt eine Möglichkeit, dies zu simulieren: put '\''. Formal beendet dies das Literal in einfachen Anführungszeichen, hängt ein wörtliches einfaches Anführungszeichen an und beginnt ein neues Literal in einfachen Anführungszeichen, aber Sie können sich die vierstellige Sequenz '\''als eine Möglichkeit vorstellen, ein einfaches Anführungszeichen in eine Zeichenfolge in einfachen Anführungszeichen zu setzen.

sh -c 'bash -c '\''a=1; echo a$a;'\'''

''Das können Sie am Ende weglassen , es ist weniger systematisch, aber angenehmer für die Augen.

sh -c 'bash -c '\''a=1; echo a$a;'\'

Einfache Anführungszeichen haben innerhalb von doppelten Anführungszeichen keine besondere Bedeutung. Daher benötigen Sie beim Schreiben "bash -c 'a=1; echo a\$a;'"einen Backslash vor dem Dollarzeichen, um die Erweiterung $ain der äußeren Hülle zu verhindern.

Antwort2

Nun, ich habe ein paar gefunden, die funktionieren (NB, dies ist Ubuntu 11.04):

$ sh -c "bash -c 'a=1; echo a\$a \'"
a1
$ sh -c "bash -c 'a=1; echo a\$a;'"
a1

... und es scheint, dass es funktioniert, solange das erste einfache Anführungszeichen nicht maskiert ist und das Dollarzeichen maskiert ist, unabhängig davon, ob das letzte einfache Anführungszeichen maskiert ist oder nicht! Was mich immer noch ziemlich verwirrt ...

verwandte Informationen