Bash

在命令行上表示/引用 NUL

  • November 24, 2017

可以\0在命令行上使用嗎?

背景

為了在 GNU Parallel 中測試極端情況,我很好奇命令行中是否正確引用了所有字元。其中大多數是:

perl -e 'print pack ("c*",1..255,10)' | parallel -k echo | md5sum
d03484ca75b3e38be411198d66bf4611  -
perl -e 'print pack ("c*",1..255,10)' | md5sum
d03484ca75b3e38be411198d66bf4611  -

\0似乎很棘手(這裡用 說明A\0B\n):

perl -e 'print pack ("c*",65,0,66,10)' | wc -c
4 (A\0B\n)
perl -e 'print pack ("c*",65,0,66,10)' | parallel echo | wc -c
2 (A\n)
perl -e 'print pack ("c*",65,0,66,10)' | parallel --dry-run echo | wc -c
9 (echo A\0B\n)
perl -e 'print "echo ",pack ("c*",65,0,66,10)' | bash | wc -c
3 (AB\n)

我可以證明第二個範例的合理性:\0可能被解釋為 EOS,但範例 4 中也應該是這種情況。範例 3 強調 GNU Parallel 不\0將其視為 EOS,而是將其傳遞給bash.

你能解釋一下發生了什麼嗎?尤其是案例 4 讓我很困惑。

更重要的是:

有沒有辦法\0在命令行上引用,以便例如echo看到它?

執行命令時,參數列表是傳遞給execve()系統呼叫的指向以 NUL 結尾的字元串的指針列表(就像傳遞給的另一個以 NUL 結尾的字元串列表的環境變數一樣execve())。

因此,執行命令的參數和環境變數不能包含 NUL 字元。

例外是 shell 中的內置函式和函式,zsh其參數可以包含任何內容(這些是內置的,因此execve()不涉及系統呼叫)。

您可以通過標準輸入(或任何其他文件描述符)或任何類型的文件傳遞帶有 NUL 字元的數據。或者某些命令理解某種形式的編碼。

例如,符合 UNIX的echo實現\0將(兩個字元反斜杠和零)理解為表示 NUL 字元。其他一些實現只有在傳遞-e標誌時才會這樣做。

所以:

echo '\0'

或者:

echo -e '\0'

可能導致echo輸出 NUL 字元後跟 LF 字元。

zsh,

echo $'\0'

將 NUL 字元傳遞給echo內置函式。

/bin/echo $'\0'

不起作用,因為/bin/echois executed,所以它的參數不能包含 NUL 字元。

至於你的第4點問題。只是 bash 忽略了那些 NUL 字元。其他一些 shell 的行為不同。

$ printf 'e\0cho a\0b\n' | bash |& sed -n l
ab$
$ printf 'e\0cho a\0b\n' | ksh |& sed -n l
ksh: syntax error at line 1: `zero byte' unexpected$
$ printf 'e\0cho a\0b\n' | zsh |& sed -n l
zsh: command not found: e$
$ printf 'e\0cho a\0b\n' | rc |& sed -n l
line 1: warning: null character ignored$
line 1: warning: null character ignored$
ab$

引用自:https://unix.stackexchange.com/questions/160598