如何忽略“命令替换:忽略输入中的空字节”?

如何忽略“命令替换:忽略输入中的空字节”?

我有这个 Linux shell 命令:

echo $(python3 -c 'print("Test"+"\0"+"M"*18)') | nc -u [IP] [PORT]

我的目的是将语句的输出通过管道传递print给 netcat 命令。 netcat 命令创建一个到某些服务的套接字,该服务本质上返回传入字符串的标准输出。

这里的问题是,当我尝试运行此命令时,我收到此消息: -bash: warning: command substitution: ignored null byte in input;我的空字节\0被忽略。但我不希望忽略空字节。

如何告诉系统不要忽略我的空字节并完全按照我指定的方式接收输入。

我已经进行了一些谷歌搜索,但老实说,它们没有多大帮助。此外,非常感谢任何精彩文章的链接。


编辑

使用printf有效。

一般情况下通过python3 -c 'print("Test"+"\0"+"M"*18)'也有效。有价值的@cas 解释。我想我可能会坚持使用printf它,因为它更快(尽管速度在我的情况下并不是特别重要)。

感谢所有贡献者:-)。

答案1

bash 中的字符串不能包含一个 NUL 字节,并且包括命令替换的任何输出。 Bash 变量也不能包含 NUL。这不能被忽略或覆盖(尽管它可以在某些命令中解决,例如printf,通过用作\0NUL 的表示,与\n换行符的表示相同)。

您可以将 python 的输出直接通过管道传输到nc,而不需要echo命令替换(如 @CharlieWilson 的答案),但即使这样也是没有必要的。 bash 的printf内置功能可以做你想做的事情。例如

{ printf 'Test\0'; printf -- '%.0sM' {1..18}; } | nc -u [IP] [PORT]

这使用组命令 ( { list; }) 首先使用\0printf 打印“Test”和一个 NUL 字节 ( ),然后再次使用 printf 打印一个零宽度字符串 ( %.0s),后跟M18 次。整个组命令的输出通过管道传输到nc.

这是可行的,因为该printf格式“根据需要重新使用以消耗所有参数”(请参阅​​ 参考资料help printf),并且大括号扩展扩展{1..18}为从 1 到 18 的整数,为只有一个零的 printf 格式字符串提供了 18 个参数-width 字符串字段和文字“M”字符。因此,输出了 18 M 个字符。

您可以通过将组命令通过管道传输到十六进制转储器(例如xxd或)来准确查看其输出内容,hd而不是nc

$ { printf 'Test\0'; printf -- '%.0sM' {1..18}; } | hd
00000000  54 65 73 74 00 4d 4d 4d  4d 4d 4d 4d 4d 4d 4d 4d  |Test.MMMMMMMMMMM|
00000010  4d 4d 4d 4d 4d 4d 4d                              |MMMMMMM|
00000017

这样,您可以看到第五个字符是 NUL ( 00)。

python 的输出略有不同,因为 pythonprint自动附加换行符 ( 0a):

$ python3 -c 'print("Test"+"\0"+"M"*18)' | hd
00000000  54 65 73 74 00 4d 4d 4d  4d 4d 4d 4d 4d 4d 4d 4d  |Test.MMMMMMMMMMM|
00000010  4d 4d 4d 4d 4d 4d 4d 0a                           |MMMMMMM.|
00000018

如果您要发送的程序nc需要换行符,您可以使用 打印它printf '\n'。或与echo.

$ { printf 'Test\0'; printf -- '%.0sM' {1..18}; echo; } | hd
00000000  54 65 73 74 00 4d 4d 4d  4d 4d 4d 4d 4d 4d 4d 4d  |Test.MMMMMMMMMMM|
00000010  4d 4d 4d 4d 4d 4d 4d 0a                           |MMMMMMM.|
00000018

仅供参考:有关组命令的更多信息,请参阅man bash并搜索Compound Commands

{ list; }

list只是在当前 shell 环境中执行。list 必须以换行符或分号终止。

这称为组命令。返回状态是list的退出状态。

请注意,与元字符(和不同){}是保留字,并且必须出现在允许识别保留字的地方。由于它们不会导致断字,因此必须list用空格或其他 shell 元字符将它们分隔开。


顺便说一句,使用 printf 会比使用 python 更快,因为它避免了执行 python 和编译小 python 脚本的开销...这对于任何类似于现代系统的一次性命令都是无关的,但如果循环运行。例如,在我大约 10 年前的 6 核 AMD Phenom II 1090T 上:

$ time { printf 'Test\0'; printf -- '%.0sM' {1..18}; } 
TestMMMMMMMMMMMMMMMMMM
real 0m0.000s   user 0m0.000s   sys 0m0.000s

$ time python3 -c 'print("Test"+"\0"+"M"*18)' 
TestMMMMMMMMMMMMMMMMMM

real 0m0.036s   user 0m0.028s   sys 0m0.008s

printf 实际上并不需要 0 秒,它需要更多时间,但是时间量太小,无法用我的 $TIMEFORMAT 字符串表示。

Perl 的启动、编译和运行其小脚本的速度比 Python 快一些,但您仍然不想在 shell 循环中重复运行它:

$ time perl -e 'print "Test\0" . "M" x 18 . "\n"' 
TestMMMMMMMMMMMMMMMMMM

real 0m0.008s   user 0m0.000s   sys 0m0.009s

或者使用 Perl 的 printf 甚至更快:

$ time perl -e 'printf "Test\0%s\n", "M" x 18' 
TestMMMMMMMMMMMMMMMMMM

real 0m0.003s   user 0m0.003s   sys 0m0.000s

答案2

我相信这echo就是问题所在,而且是不必要的。

请考虑这一行。

python3 -c 'print("Test"+"\0"+"M"*18)' | nc -u [IP] [PORT]

相关内容