将 `echo` 的管道输出发送到 netcat 失败,而 `printf` 的管道输出通过

Gab*_*les 5 bash shell netcat

我正在 Linux Ubuntu 18.04 和 20.04 上使用( ) 通过 TCP 以太网向Teledyne LeCroy T3PS3000电源设备发送命令。如果我使用该设备无法正确接收命令,但如果我使用它则工作正常。为什么?netcatncechoprintf

# Example command to Ethernet-connected digital power supply over TCP

# fails
echo 'measure:voltage? ch1' | timeout 0.2 nc 192.168.0.1 5025

# works
printf 'measure:voltage? ch1' | timeout 0.2 nc 192.168.0.1 5025
Run Code Online (Sandbox Code Playgroud)

参考:

  1. timeoutcmd: https: //unix.stackexchange.com/questions/492766/usage-of-nc-with-timeouts-in-ms/492796#492796
    1. 更新/注意(在我写完答案之后写的,所以printf下面的表格是正确的):如果没有该timeout命令,我们将不得不使用-w带有 的选项netcat,但它只接受以秒为单位的整个整数等待周期超时,如下所示(-w 1注意将“等待”时间或超时设置为 1 整秒):
      printf '%s' "my command to send" | nc -w1 192.168.0.1 5025 
      
      Run Code Online (Sandbox Code Playgroud)
  2. Teledyne LeCroy T3PS3000电源:来自我的git 和 Linux cmd、帮助、提示和技巧 -我的eRCaGuy_dotfiles存储库中的 Gabriel.txt 文档:
    1. 如需帮助,请联系:
      Teledyne LeCroy 支持
      support@teledynelecroy.com
      700 Chestnut Ridge Road
      Chestnut Ridge, NY 10977
      (800) 553-2769 选项 3
    2. 手册中没有,所以我给他们发了电子邮件,他们告诉我:

      T3PS3000采用socket通信方式,默认端口为5025。

    3. 手册(快速入门指南):http://cdn.teledynelecroy.com/files/manuals/t3ps3000-quick-start-guide.pdf
      • p24,“第 3 章远程控制”是命令界面开始的地方。

Gab*_*les 7

啊! 找到了。

\n确保您不会意外在命令末尾发送换行符 ( )

它看起来像是echo在字符串中添加了一个尾随换行符,但printf事实并非如此,并且这个尾随换行符会干扰设备解析命令的能力。如果我强行将它(换行符,\n)添加到 cmd 的末尾printf,那么它也会失败 - 这意味着设备不会按预期响应命令:

# fails:
printf 'measure:voltage? ch1\n' | timeout 0.2 nc 192.168.0.1 9999
Run Code Online (Sandbox Code Playgroud)

...看起来您可以echo通过使用以下命令来抑制尾随换行符-n

# works!
echo -n 'measure:voltage? ch1' | timeout 0.2 nc 192.168.0.1 9999

# also works, of course, as stated in the question
printf 'measure:voltage? ch1' | timeout 0.2 nc 192.168.0.1 9999
Run Code Online (Sandbox Code Playgroud)

man echo

-n     do not output the trailing newline
Run Code Online (Sandbox Code Playgroud)

要点:在打印的末尾使用printfecho -n不使用尾随换行符。

但是,这还没有结束!这里还有两点:

1. 如果您想要可移植和预期的行为,以及向设备发送任何命令的能力,请不要在任何 shell 脚本中echo 使用

当尝试使用它向设备发送任何可能的字符串时,使用echo at确实是一个坏主意!为什么?好吧,@Jeff Schaller在评论中向我指出了以下资源,其中包含大量真正有价值的信息:Unix & Linux:为什么 printf 比 echo 更好?

不使用的一些关键原因echo包括:

  1. 它的实现、参数和行为都有点hacky。

  2. 它不可移植:它有多种实现方式,在不同的系统中差异很大。有些支持-e-n有些不支持。有些-e行为默认情况下没有-e. ETC。

  3. 在某些 shell 上,它根本-n无法作为命令打印。请参阅我的评论

    在 Ubuntu 18.04 和 20.04 上的 bash 上,echo "-n"应该输出-n. 相反,它不输出任何内容,因为它接受与标志相同的东西-necho -- "-n"应该解决这个问题并输出-n,但事实并非如此。它-- -n反而输出。我现在非常明白你的观点了。printf更好。

  4. 正如@Charles Duffy在评论中指出的那样:由于许多不一致和原因,即使是POSIX 规范也echo建议不要使用:echo

    不可能echo在所有 POSIX 系统上移植使用...

    鼓励新应用程序使用printf而不是echo.

仅供参考,这里有一些来自Unix 和 Linux 的关键引言: 为什么 printf 比 echo 更好?:

关于echo

...确保$var不包含反斜杠字符并且不以-

关于printf

但请记住第一个参数是格式,因此不应包含可变/不受控制的数据。

2.printf 正确使用as printf '%s' "my command string", NOTprintf "my command string"

请参阅下面的评论中我和@Charles Duffy 之间的更多讨论。你应该printf这样使用:

-n     do not output the trailing newline
Run Code Online (Sandbox Code Playgroud)

这是因为传递给的第一个参数printf被解析为格式字符串。例如,如果您尝试发送到设备的命令字符串是%s,则不会发送任何内容!:

# CORRECT USAGE: >>> FINAL ANSWER; DO THIS! <<<
printf '%s' 'measure:voltage? ch1' | timeout 0.2 nc 192.168.0.1 9999  

# NOT this:
printf 'measure:voltage? ch1' | timeout 0.2 nc 192.168.0.1 9999
Run Code Online (Sandbox Code Playgroud)

输出为空,因为printf将第一个参数解释为格式字符串,并且%s表示格式字符串中的特殊内容。但这确实%s以文字形式发送:

printf "%s"
Run Code Online (Sandbox Code Playgroud)

输出是

%s
Run Code Online (Sandbox Code Playgroud)

根据规范,"%s"参数中的第一个printf格式字符串,第二个"s"是要替换为第一个所在格式字符串的字符串文字%sprintf

这意味着正确的使用printf将能够向设备发送任何命令,而错误的使用将删除任何格式字符,例如%s%02X%u等 - 任何printf-style 格式字符串特殊字符或序列

也可以看看:

  1. Unix 和 Linux:为什么 printf 比 echo 更好?
  2. POSIX 规范echo
  3. 我的netcat教程:ServerFault:一般netcat( nc)使用说明,包括设置接收时绑定的IP地址,或发送时发送到的IP地址

  • 顺便说一句,使用 `printf '%s' "string"` 比使用 `printf "string"` 更可靠,因为前者强制将字符串视为文字而不是格式字符串。 (4认同)
  • 有关更多背景信息(请注意“echo”的各种实现以及“这意味着您不能使用 echo 来显示不受控制的数据”):https://unix.stackexchange.com/questions/65803/why-is -printf 比 echo 更好 (2认同)