我一直在尝试建立一个 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