在命令行中表示/引用 NUL

在命令行中表示/引用 NUL

可以\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 并不将其视为\0EOS,而是将其传递给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$

相关内容