可以\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
在命令行上引用以便egecho
看到它?
答案1
执行命令时,参数列表是传递给execve()
系统调用的指向 NUL 终止字符串的指针列表(就像环境变量,它是传递给 的另一个 NUL 终止字符串列表execve()
)。
结果,参数和环境变量被处决命令不能包含 NUL 字符。
例外的是 shell 中的内置函数和函数,zsh
它们的参数可以包含任何内容(它们是内置的,因此execve()
不涉及系统调用)。
您可以通过 stdin(或任何其他文件描述符)或在任何类型的文件中传递带有 NUL 字符的数据。或者某些命令理解某种形式的编码。
例如,符合 UNIX 规范的echo
实现将(两个字符反斜杠和零)理解\0
为 NUL 字符。其他一些实现仅在传递-e
标志时才执行此操作。
所以:
echo '\0'
或者:
echo -e '\0'
可能会导致echo
输出 NUL 字符,后跟 LF 字符。
和zsh
,
echo $'\0'
将 NUL 字符传递给echo
内置字符。
/bin/echo $'\0'
不会工作,因为/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$