2013-10-07 8 views
15

ermöglicht $'string' Erweiterung. Mein man bash sagt:

Worte der Form $'string' sind speziell behandelt. Das Wort wird auf string erweitert, wobei Zeichen mit Backslash-Escapezeichen wie im ANSI C-Standard angegeben ersetzt werden. Aufkantung Escape-Sequenzen, falls vorhanden, dekodiert werden, wie folgt:
\a alert (Glocke)
\b Backspace
\e
\E ein Escape-Zeichen
\f Formularvorschub
\n neue Linie
\r Wagenrücklauf
\t horizontale Registerkarte
\v vertikaler Lasche
\ Backslash
\' Apostroph
\" doppeltes Anführungszeichen
\nnn die Acht-Bit-Zeichen, dessen Wert die Oktalwert nnn (2.59 digits)
\xHH die Acht-Bit-Zeichen, das Wert ist der Hexadezimalwert HH (ein oder zwei Hexadezimalzeichen)
\cx ein Steuer- x Charakter

Das erweiterte Ergebnis ist in einfachen Anführungszeichen, als ob das Dollarzeichen nicht anwesend war.

Aber warum nicht $'\0' und $'\x0' in ein Null-Zeichen konvertieren?
Ist es dokumentiert? Gibt es einen Grund? (Ist es ein Merkmal oder eine Einschränkung oder sogar ein Bug?)

$ hexdump -c <<< _$'\0'$'\x1\x2\x3\x4_' 
0000000 _ 001 002 003 004 _ \n 
0000007 

echo das erwartete Ergebnis liefert:

> hexdump -c < <(echo -e '_\x0\x1\x2\x3_') 
0000000 _ \0 001 002 003 _ \n 
0000007 

Meine bash Version

$ bash --version | head -n 1 
GNU bash, version 4.1.2(1)-release (x86_64-redhat-linux-gnu) 

Warum echo $'foo\0bar' nicht benimmt als echo -e 'foo\0bar'?

+3

Gute Frage! Vielleicht ist es eine Posix-Sache? Viel Glück. – shellter

+0

Danke für alle Antworten. Ich habe das gleiche Problem bei der Verwendung von Netcat, um die SGCI-Schnittstelle zu einem Server zu testen. Der SCGI-Header hat NUL-Zeichen. Nachdem ich hier gelesen habe, vor allem den Vorschlag, Pipes zu verwenden, habe ich einen Workaround entwickelt. Ich benutze Oktal 377 (ASCII 255), wo die NUL-Zeichen sein müssen, und dann pipe die Zeichenfolge durch tr, kurz bevor es in Netcat Xmlreq = ' system.client_version 'scgihdr = CONTENT_LENGTH $' \ 377 '$ {# xmlreq} $' \ 377'SCGI $ '\ 377'1 $' \ 377' echo -n $ {# scgihdr –

Antwort

20

Es ist eine Einschränkung. bash erlaubt String-Werten nicht, interne NUL-Bytes zu enthalten.

Posix- (und C-) Zeichenfolgen können keine internen NULs enthalten. Siehe zum Beispiel: (Hervorhebung hinzugefügt) die Posix definition der Zeichenkette:

3,92 Zeichenkette

eine zusammenhängende Sequenz von Zeichen terminierte durch und einschließlich dem ersten Nullbyte.

Ähnlich Standard-C über die NUL-Zeichen in Zeichenketten maßen explizit:

§ 5.2.1p2 & hellip; Ein Byte mit allen auf 0 gesetzt Bits, die Nullzeichen genannt, soll bestehen in der grundlegende Ausführungszeichensatz; es wird verwendet, um eine Zeichenkette zu beenden.

Posix verbietet ausdrücklich die Verwendung von NUL (und /) in Dateinamen (XBD 3.170) oder in Umgebungsvariablen (XBD 8.1 "... betrachtet ist mit einem Null-Byte zu beenden."

In diesem Kontext, Shell-Befehlssprachen, einschließlich bash, neigen dazu, die gleiche Definition einer Zeichenkette zu verwenden, wie eine Folge von Nicht-NULL-Zeichen, die durch eine einzige NUL beendet werden. und nichts hindert Sie daran, der Ausgabe eines Programms, das ein NUL-Byte ausgibt, eine Shell-Variable zuzuordnen, die Konsequenzen sind jedoch "unspezifiziert" ac Nach Posix (XSH 2.6.3 "Wenn die Ausgabe irgendwelche Nullbytes enthält, ist das Verhalten nicht spezifiziert."). In bash werden die NULs entfernt, es sei denn, Sie fügen eine NUL mit der C-Escape-Syntax von bash in eine Zeichenfolge ein ($'\0'). In diesem Fall beendet die NUL den Wert.

Auf einer praktischen Anmerkung, betrachten Sie den Unterschied zwischen den beiden folgenden Möglichkeiten einen NUL in die stdin eines Gebrauchs- einzufügen versuchen:

$ # Prefer printf to echo -n 
$ printf $'foo\0bar' | wc -c 
3 
$ printf 'foo\0bar' | wc -c 
7 
$ # Bash extension which is better for strings which might contain % 
$ printf %b 'foo\0bar' | wc -c 
7 
+1

Große Info. Re: "nichts hält Sie davon ab, eine Shell-Variable der Ausgabe eines Programms zuzuweisen, das eine NUL ausgibt" - es ist erwähnenswert, dass der Wert der Variablen bei der ersten NUL, die angetroffen wird, ausnahmslos abgeschnitten wird. Re "Wenn Sie eine NUL in eine Zeichenkette einfügen, indem Sie eine der backslash Escape-Sequenzen von bash verwenden ($ '\ 0'), wird der Wert beendet." - Um zu verdeutlichen: Einfügen von '$ '\ 0'' in _another_ string wird _not_ nicht den gesamten String beenden, sondern einfach den' $' \ 0'' ignorieren; z.B. 'a $' \ 0'b '->' ab '; a '\ 0' _inside_' $ '...' 'jedoch _will_ die Zeichenfolge dort abschneiden; z. B. "$ 'a \ 0b'" -> "a". – mklement0

+1

@ mklement0: Ja, das habe ich vor zwei Jahren falsch verstanden. Vielen Dank. Korrigiert jetzt, glaube ich. – rici

+0

Danke für die Aktualisierung. Erneutes Zuweisen einer Befehlsausgabe zu einer Variablen: Da 'bash'-Variablenwerte intern als C-Zeichenfolgen gespeichert sind, können sie niemals NULs enthalten. Es ist jedoch sinnvoll, zwischen (a) 'var = $ (...)' zu unterscheiden. In diesem Fall werden alle NULs einfach _striped_, also der Wert, der per definitionem zugewiesen wird nie enthält NULs, aber enthält _all other other_ Zeichen und (b) 'read -rd '' var <<(....)', wobei die Eingabe NULs enthalten kann, aber 'read' kein Lesen über die erste NUL hinaus erlaubt und der Wert deshalb _cut off_ at ist die erste NUL. – mklement0

3

Es ist ein Null-Zeichen, aber es hängt davon ab, was Sie damit meinen.

Das Nullzeichen steht für eine leere Zeichenfolge, die beim Erweitern erhalten wird. Es ist ein Sonderfall, und ich denke, das ist in der Dokumentation impliziert, aber nicht wirklich angegeben.

In C binär Null '\0' beendet eine Zeichenfolge und stellt auch eine leere Zeichenfolge. Bash ist in C geschrieben, daher folgt daraus wahrscheinlich.

Edit: POSIX erwähnt eine Null-Zeichenfolge an mehreren Stellen. In der "Basis Definitionen" definiert sie eine Null-Zeichenkette als:

3,146 leere Zeichenfolge (oder Null-String)
A-Saite, deren erstes Byte ist ein Null-Byte.

5

Aber warum nicht $'\0' und $'\x0' in ein Null-Zeichen ist bash konvertieren?

Da ein Nullzeichen eine Zeichenfolge beendet.

$ echo $'hey\0you' 
hey