per*_*ror 5 bash stdin gdb named-pipes
我最近发现提供调试程序的<<<技巧是从流中过滤掉空字节。gdbstdin
这是一个小例子(任何人都应该能够在家里重现)来证明它过滤掉了空字节:
$> 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]
Run Code Online (Sandbox Code Playgroud)
其中,使用特定于 bash 的<() 进程替换将空字节保留到以下程序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]
Run Code Online (Sandbox Code Playgroud)
所以,我一直认为<<<并且<()正在做同样的事情,现在显然是错误的。我想知道这两种方法之间有什么区别,并对bash神秘的错误消息进行解释,说明:
/bin/bash: warning: command substitution: ignored null byte in input
Run Code Online (Sandbox Code Playgroud)
任何帮助都非常受欢迎!
所以,我一直这么想
<<<,并且<()正在做同样的事情,但现在显然是错误的。
这些根本不做同样的事情。该<<<操作符将“此处字符串”重定向到关联进程的标准输入。进程替换 via<() 扩展为文件名(通常是 FIFO 或类似文件),可以从中读取给定命令的标准输出。
您的意思似乎是,<<<与命令替换(通过$()或反引号)的组合与通过进程替换的普通标准输入重定向的组合具有相同的作用<。 这是事实,但正如您所发现的,语义并不完全等同。
我想知道这两种方法有什么区别,并对bash神秘错误消息有解释
关键区别在于,从此处字符串重定向需要首先生成字符串作为 shell 保存的值(您通过命令替换执行此操作),而重定向进程替换涉及由关联进程直接读取重定向的输出。
最终,您收到的诊断表明您遇到的意外行为是由命令替换的行为引起的,而不是<<<. 虽然我没有发现它有明确的记录,但我对 Bash 在处理命令替换时从程序输出中删除空字符一点也不感到惊讶,因为我希望它的 shell 字符串的内部表示形式是 C 字符串。C 字符串以 null 结尾,因此不能表示包含 null 字符的字符序列。
更新:
另请注意,正如 @sorontar 在其他答案的评论中观察到的那样,POSIX 表示如果命令替换中的命令输出包含空字节,则结果未指定。因此,Bash 可以自由地剥离空字节——或者实际上在看到它们时或多或少地做任何它想做的事情——而不会牺牲 POSIX 一致性。其他 shell 在这方面可能会做出与 Bash 不同的选择。这是避免命令替换的一个很好的理由,因为命令输出中出现空字节是可预见的可能性。