Ole*_*nge 7 shell bash special-characters quoting binary
可以\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 -
Run Code Online (Sandbox Code Playgroud)
但\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)
Run Code Online (Sandbox Code Playgroud)
我可以证明第二个示例是合理的:\0可能被解释为 EOS,但在示例 4 中也应该如此。示例 3 强调 GNU Parallel 不会\0将其视为 EOS,而是将其传递给bash.
你能解释一下发生了什么——尤其是案例 4 让我感到困惑。
更重要的是:
有没有办法\0在命令行上引用以便例如echo看到它?
执行命令时,参数列表是指向传递给execve()系统调用的NUL 终止字符串的指针列表(就像传递给的另一个 NUL 终止字符串列表的环境变量一样execve())。
因此,执行命令的参数和环境变量不能包含 NUL 字符。
例外的是zshshell中的内置函数和函数,它们的参数可以包含任何内容(它们是内置的,因此execve()不涉及系统调用)。
您可以通过 stdin(或任何其他文件描述符)或任何类型的文件传递带有 NUL 字符的数据。或者一些命令理解某种形式的编码。
例如,符合 UNIX 的echo实现将\0(两个字符反斜杠和零)理解为 NUL 字符。其他一些实现只有在传递-e标志时才会这样做。
所以:
echo '\0'
Run Code Online (Sandbox Code Playgroud)
或者:
echo -e '\0'
Run Code Online (Sandbox Code Playgroud)
可能导致echo输出 NUL 字符后跟 LF 字符。
与zsh,
echo $'\0'
Run Code Online (Sandbox Code Playgroud)
将 NUL 字符传递给echo内置函数。
/bin/echo $'\0'
Run Code Online (Sandbox Code Playgroud)
不会工作,因为/bin/echo被执行,所以它的参数不能包含 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$
Run Code Online (Sandbox Code Playgroud)