我最近发现,<<<
中的gdb
技巧可以提供调试程序的stdin
,从流中过滤掉空字节。
这是一个小例子(任何人都应该能够在家重现)来证明它过滤掉了空字节:
$> python -c 'print("A\x00" * 10)' | cat -A
A^@A^@A^@A^@A^@A^@A^@A^@A^@A^@$
$> gdb /bin/cat
... gdb license prelude ... snip...
(gdb) r -A <<< $(python -c 'print("A\x00" * 10)')
Starting program: /bin/cat -A <<< $(python -c 'print("A\x00" * 10)')
/bin/bash: warning: command substitution: ignored null byte in input
AAAAAAAAAA$
[Inferior 1 (process 3798) exited normally]
其中,使用特定于bash的<()
process substitution,空字节到达stdin
内的程序gdb
:
(gdb) r -A < <(python -c 'print("A\x00" * 10)')
Starting program: /bin/cat -A < <(python -c 'print("A\x00" * 10)')
A^@A^@A^@A^@A^@A^@A^@A^@A^@A^@$
[Inferior 1 (process 3804) exited normally]
所以,我一直认为<<<
和<()
正在做同样的事情,现在显然是错的。我想知道这两种方法之间有什么区别,并对bash
神秘的错误消息做出解释,说明:
/bin/bash: warning: command substitution: ignored null byte in input
非常欢迎任何帮助!
答案 0 :(得分:3)
如前所述,这两种方法并不相同(尽管在某些情况下可以出于同样的原因使用)
此<<<
是此字符串,受可变扩展规则约束。 Bash不允许在变量值处出现空字节。
另一方面,进程替换<()
被视为文件,文件中允许使用空字符。
所以你注意到的差异是由于这种bash行为造成的。 使用不同的shell可能此限制无效。
更多测试:
$ echo -en "A\x00A\x00A" |od -t x1c
0000000 41 00 41 00 41
A \0 A \0 A
0000005
$ a=$(echo -en "A\x00A\x00A");echo "$a" |od -t x1c
bash: warning: command substitution: ignored null byte in input
0000000 41 41 41 0a
A A A \n
0000004
$ cat <(echo -en "A\x00A\x00A") |od -t x1c #this is treated as file
0000000 41 00 41 00 41
A \0 A \0 A
0000005
$ cat <<<$(echo -en "A\x00A\x00A") |od -t x1c #this is considered a variable
bash: warning: command substitution: ignored null byte in input
0000000 41 41 41 0a
A A A \n
0000004
答案 1 :(得分:2)
所以,我总是认为
<<<
和<()
正在做同样的事情,现在显然是错的。
那些根本不做同样的事情。 <<<
运算符重定向 a&#34; here string&#34;到相关过程的标准输入。通过<()
进行的进程替换扩展为可以从中读取给定命令的标准输出的文件名(通常是FIFO或类似名称)。
你的意思是<<<
与命令替换(通过$()
或反引号)的组合与通过<
的普通标准输入重定向的组合完全相同进程替换。 这是正确的,但正如您所发现的,语义并不完全等效。
我想知道两种方法之间有什么区别,并对bash神秘错误消息进行解释
关键的区别在于,从here字符串重定向需要首先将字符串生成为shell保存的值(您通过命令替换执行此操作),而重定向进程替换涉及重定向输出被读取通过相关流程直接。
最终,您收到的诊断表明您遇到的意外行为来自命令替换的行为,而不是<<<
的行为。虽然我没有明确记录,但是当Bash在处理命令替换时从程序输出中删除空字符时,我并不感到惊讶,因为我希望它的shell字符串的内部表示形式为C字符串。 C字符串以空值终止,因此不能表示包含空字符的字符序列。
<强>更新强>
另请注意,正如@sorontar在对另一个答案的评论中所观察到的那样,POSIX表示如果命令替换中的命令输出包含空字节,则结果未指定。因此,Bash可以自由地删除空字节 - 或者实际上在它看到它们时做或多或少的任何事情 - 而不会牺牲POSIX一致性。在这方面,其他炮弹可能比Bash做出不同的选择。这是避免命令替换的一个很好的理由,其中命令输出中出现的空字节是可预见的可能性。