Bash verwendet intern Strings im C-Stil, die mit Null-Bytes abgeschlossen werden. Dies bedeutet, dass eine Bash-Zeichenfolge (z. B. der Wert einer Variablen oder ein Argument für einen Befehl) niemals tatsächlich ein Null-Byte enthalten kann. Zum Beispiel dieses Mini-Skript:
foobar=$'foo\0bar' # foobar='foo' + null byte + 'bar'
echo "${#foobar}" # print length of $foobar
druckt eigentlich 3
, weil $foobar
es eigentlich nur so ist 'foo'
: das bar
kommt nach dem Ende der Zeichenkette.
Ebenso wird echo $'foo\0bar'
nur gedruckt foo
, da echo
über das \0bar
Teil nichts bekannt ist .
Wie Sie sehen können, ist die \0
Sequenz in einem $'...'
String im -Stil tatsächlich sehr irreführend . Es sieht aus wie ein Null-Byte in der Zeichenfolge, aber es funktioniert nicht so. In Ihrem ersten Beispiel hat Ihr read
Befehl -d $'\0'
. Das funktioniert, aber nur weil es -d ''
auch funktioniert! (Dies ist kein explizit dokumentiertes Feature von read
, aber ich nehme an, es funktioniert aus dem gleichen Grund: Ist''
der String leer, so kommt das abschließende Null-Byte sofort. Es wird dokumentiert, dass "Das erste Zeichen von delim " verwendet wird, und ich vermute, dass dies sogar funktioniert wenn das "erste Zeichen" hinter dem Ende der Zeichenkette liegt!)-d delim
Aber wie Sie von Ihrem wissen find
Beispiel, es ist möglich , dass ein Befehl einen Null - Byte auszudrucken, und für das Byte an einem anderen Befehl geleitet werden , dass sie als Eingabe liest. Kein Teil davon ist darauf angewiesen, ein Null-Byte in einer Zeichenfolge in Bash zu speichern . Das einzige Problem mit Ihrem zweiten Beispiel ist, dass wir kein $'\0'
Argument für einen Befehl verwenden können. echo "$file"$'\0'
Am Ende könnte man gerne das Null-Byte ausgeben, wenn man nur wüsste, dass man es haben möchte.
Anstatt also zu verwenden echo
, können Sie verwenden printf
, was dieselben Arten von Escape-Sequenzen unterstützt wie $'...'
-Style-Strings. Auf diese Weise können Sie ein Null-Byte drucken, ohne dass ein Null-Byte in einer Zeichenfolge enthalten sein muss. Das würde so aussehen:
for file in * ; do printf '%s\0' "$file" ; done \
| while IFS= read -r -d '' ; do echo "$REPLY" ; done
oder einfach so:
printf '%s\0' * \
| while IFS= read -r -d '' ; do echo "$REPLY" ; done
(Hinweis: Hat echo
tatsächlich auch ein -e
Flag, mit dem \0
ein Null-Byte verarbeitet und gedruckt werden kann. Dann wird jedoch auch versucht, spezielle Sequenzen in Ihrem Dateinamen zu verarbeiten. Der printf
Ansatz ist also robuster.)
Im Übrigen gibt es einige Muscheln , die keine Null - Bytes innerhalb von Zeichenketten ermöglichen. Ihr Beispiel funktioniert beispielsweise in Zsh einwandfrei (unter der Annahme von Standardeinstellungen). Unabhängig von Ihrer Shell bieten Unix-ähnliche Betriebssysteme jedoch keine Möglichkeit, Nullbytes in Argumente für Programme einzufügen (da Programmargumente als Zeichenfolgen im C-Stil übergeben werden), sodass es immer einige Einschränkungen gibt. (Ihr Beispiel kann nur in Zsh arbeiten , weil echo
ein Shell - builtin ist, so Zsh es , ohne sich auf die OS - Unterstützung zum Aufrufen anderer Programme aufrufen kann. Wenn Sie verwendet command echo
statt echo
, so dass es die eingebaute umgangen und die Standalone verwendet echo
Programm auf das $PATH
, Sie würden das gleiche Verhalten in Zsh wie in Bash sehen.)
-d ''
bereits bedeutet, abzugrenzen\0
? Ich fand eine Erklärung hier: stackoverflow.com/questions/8677546/…