Bash 等待 ping 成功

Bash 等待 ping 成功

我正在编写一个重新启动各种服务器的脚本。重新启动后,我想“等待”直到所有服务器重新上线。(为了简单起见,我为我定义了 online=pingable)

因此对于每个服务器我都会

ServerXY_W=1
echo -n "waiting for ServerXY ..."
while (($ServerXY_W == 1))
do
   if ping -c 1 -w 0.2 192.168.123.123 &> /dev/null
   then
      echo "ServerXY is back online!"
      ServerXY_W=0
   else
      echo -n "."
   fi
done

我期望(并且喜欢)的输出是这样的

waiting for ServerXY .................
ServerXY is back online!

其中的点....会一个接一个地出现。

但实际上首先发生的是

waiting for ServerXY ...

一段时间后,当服务器恢复时,我得到了最后一个点和最后一行,例如

waiting for ServerXY ....
ServerXY is back online!

为什么 while 循环只执行两次,一次 ping 失败,一次 ping 成功?我必须进行哪些更改才能在 while 循环中添加更多点?

我也用不存在的 IP 进行了测试。但它卡住了

waiting for NonExistentServer...

当然,永远不会终止。但同样的问题,为什么没有添加........

答案1

问题

问题在于您设置了-w 0.2。当值低于 1 时,截止日期 ( -w) 和超时 ( -W) 值将被忽略。这在之前已在这个问题。当您使用时-w 1,您的脚本(我稍加修改以删除无用的部分)可以正常工作:

$ ./ping_server.sh                                                 
waiting for ServerXY ....................
Server is back online

$ cat ./ping_server.sh
#!/bin/bash
printf "%s" "waiting for ServerXY ..."
while ! ping -c 1 -n -w 1 147.153.237.192 &> /dev/null
do
    printf "%c" "."
done
printf "\n%s\n"  "Server is back online"

解决方案

显而易见的解决方案是使用-w 1。如果你确实打算使用低于 1 秒的值,则命令timeout应该更好:

$ timeout 0.2 ping -c 1 147.153.237.192                            
PING 147.153.237.192 (147.153.237.192) 56(84) bytes of data.
64 bytes from 147.153.237.192: icmp_seq=1 ttl=124 time=2.61 ms

--- 147.153.237.192 ping statistics ---
1 packets transmitted, 1 received, 0% packet loss, time 0ms
rtt min/avg/max/mdev = 2.612/2.612/2.612/0.000 ms

!再次,在循环中使用运算符:

#!/bin/bash
printf "%s" "waiting for ServerXY ..."
while ! timeout 0.2 ping -c 1 -n 147.153.237.192 &> /dev/null
do
    printf "%c" "."
done
printf "\n%s\n"  "Server is back online"

当然,相反的做法也可以应用于仅当服务器启动时才显示消息,并在服务器关闭时进行报告,例如:

$ while ping -q -c 1 172.16.127.2 >/dev/null ; do sleep 1; done ; echo "Server stopped responding"
Server stopped responding

但请注意,这并不完美:

  • 我们每秒只用 1 个数据包进行 ping。带宽低、连接性差、服务器和客户端之间的硬件有问题,ping 服务器将触发循环退出并发出误报

  • 我们依赖 ping,即使用 ICMP echo。防火墙甚至单个服务器都会阻止对 ping/ICMP echo 的响应。您可以使用ncncat这是 的改进版本nc)。上面循环中的类似内容可以很好地代替ping

    nc -w5 -z 172.16.127.2 80
    

    这样做的目的是连接到 172.16.127.2 上的 80 端口上的服务器。这样-z做是为了避免 I/O - 只需连接和断开连接。-w这样做是为了等待 5 秒钟,然后报告连接失败。当然,当您控制服务器并且知道 80 端口是开放的时候,这种方法非常有效。UPD 可以正常使用,但如果有防火墙,TCP 可能更受欢迎。

    这里的一个隐藏的好处是,如果您在特定端口上运行某些服务(例如端口 80 上的 HTTP 或 554 上的 RTSP),则无法连接到端口可能表明您的服务需要重新启动。

  • 当然,nc而且ping可能有点垃圾。更好的方法是让服务器与另一个中央服务器签到,发送定期报告,可能每小时一次;这样,如果您的服务器错过了“打卡时间”,您可能会生成错误。更好的方法是使用 Nagios 之类的服务,它可以做到这一点。但此时我们正在进入具有多台服务器的企业级计算领域。如果您家里有像 Raspberry Pi 这样的东西,您可能不需要任何复杂的东西。

相关内容