最近,我发现<<<
中的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
任何帮助都超过了欢迎!
最佳答案
那些根本不做相同的事情。 <<<
运算符将“此处字符串”重定向到关联流程的标准输入。通过<()
进行的进程替换扩展为文件名(通常是FIFO或类似文件),从中可以读取给定命令的标准输出。
您似乎要说的是<<<
与命令替换(通过$()
或反引号)的组合与通过<
与进程替换的普通标准输入重定向的组合具有相同的作用。的确如此,但是正如您所发现的,语义并不完全相同。
关键区别在于,从此处的字符串重定向需要首先将字符串生成为 shell 程序保存的值(您通过命令替换执行此操作),而重定向流程替换涉及重定向的输出直接由关联的流程读取。
最终,您收到的诊断信息表明您遇到的意外行为是由命令替换的行为引起的,而不是<<<
的行为引起的。尽管我没有找到它的明确记录,但是当Bash处理命令替换时,它会从程序输出中删除空字符,这一点也不令我感到惊讶,因为我希望它的内部shell字符串表示形式为C字符串。 C字符串以Null结尾,因此不能表示包含Null字符的字符序列。
更新:
还要注意,正如@sorontar在另一个答案的注释中观察到的那样,POSIX说,如果在命令替换中命令的输出包含空字节,则结果不确定。因此,Bash可以自由剥离空字节-甚至可以在看到空字节时进行更多或更少的操作-而无需牺牲POSIX一致性。在这方面,其他shell可能会与Bash做出不同的选择。这是避免命令替换的绝佳原因,因为在命令输出中出现空字节是可以预见的可能性。
关于bash - 为什么 '<<<'过滤gdb中的空字节,而 '<()'没有呢?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/42954927/