为什么在 Bash 命令替换子 shell 中找不到“/bin/ping”?

为什么在 Bash 命令替换子 shell 中找不到“/bin/ping”?

我一直在尝试建立一个 bash 循环来检查它是否可以 ping 远程地址:

if $( /bin/ping -c 1 x.x.x.x ) ; then echo 'ok' ; fi

但我明白了PING: command not found。我不太清楚为什么会发生这种情况。

真正奇怪的是,如果我这样做:

if $( /bin/ping  x.x.x.x ) ; then echo 'ok' ; fi

(即没有-c 1)则 shell 会阻塞直到我中断(因为 ping 处于无限循环中)。

谁能解释一下发生了什么事?

(是的,我可以在顶级 shell 中运行它并进行测试$?,但为什么它没有按我预期的方式工作?这是在 Ubuntu 上的 Bash 中,如果有任何变化的话。)

答案1

你的期望是错误的,因为命令替换不会给你 $? 退出状态 - 它给你命令的标准输出文本

请记住,bash 的“if”不直接处理字符串或数字。“if..then”之间的条件始终用作命令,分支取决于其退出状态是零还是非零。换句话说,“if”通过它自己已经只不过是一张 $? 支票了。

因此,如果您想替换手动 $? 比较,您可以这样做而无需任何其他语法功能,如下所示:

if ping -c1 $addr; then echo ok; fi

但是当你使用命令替换时——无论是作为“if”条件还是作为独立命令——你都在告诉 shell 运行所提供的命令标准输出作为真正的命令。因此通常的输出如下所示:

$ ping -c1 8.8.8.8
PING 8.8.8.8 (8.8.8.8) 56(84) bytes of data.
64 bytes from 8.8.8.8: icmp_seq=1 ttl=58 time=1.39 ms

您的命令替换将产生类似以下扩展的结果:

if PING 8.8.8.8 (8.8.8.8) 56(84) bytes of data.; then echo ok; fi

希望现在已经很明显了,这会告诉 shellPING以大量参数作为实际的“if”条件来运行该命令。

(我仅使用了第一行以使示例简短,但实际上使用了整个多行字符串 - 命令替换等待进程结束。如果进程无限运行,那么 $() 也将永远收集输出并且永远不会返回。)


附注 1:有一个非常相似语法,使用 just( )代替$( ),效果完全不同。一些由 C 程序员编写的 bash 脚本可能会这样做:

if ( ping -c 1 $addr ); then...

这是有效的(尽管完全没有必要),因为它不是命令替换,而仅仅是命令分组,并且与 相同if ping...;

附注 2:这里有命令替换的有效情况,但通常它不单独使用 - 最常见的用法是与字符串比较运算符一起使用,例如:

if [ "$(whoami)" = "root" ]; then echo ok; fi

相关内容