为什么'<<<<<在gdb中过滤空字节,其中'<()'没有?

时间:2017-03-22 14:43:42

标签: bash gdb stdin named-pipes

我最近发现,<<<中的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

非常欢迎任何帮助!

2 个答案:

答案 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做出不同的选择。这是避免命令替换的一个很好的理由,其中命令输出中出现的空字节是可预见的可能性。