使用bash脚本中的ping命令来检查主机可用性

98

我想编写一个脚本,可以不断检查网络中应该全天在线的设备是否真的在线。我尝试使用ping命令,但是...

if [ "`ping -c 1 some_ip_here`" ]
then
  echo 1
else
  echo 0
fi

无论我输入有效还是无效的IP地址,都会返回1。如何检查特定地址(或更好地,来自IP地址列表的任何设备)是否离线?


1
你应该考虑使用 nmap,它允许你指定 IP 地址范围。 - devnull
就你的片段而言,据我测试,它是可以正常运行的。 - Torsten Bronger
虽然这不是答案,但最好使用“$(ping -c 1 some_ip_here)”而不是“ping -c 1 some_ip_here”。参考此链接以获取更多信息 - Anubis
1
没有人解释你的脚本的实际问题。你所写的代码会获取ping命令打印的所有输出,然后检查是否为非空字符串。由于无论成功与否,ping命令总是会打印出一些内容,因此它永远不会打印空字符串。要检查一个命令是否成功,不需要用反引号、引号或括号将其包围起来。只需直接写if cmd; then ... fi即可。 - Jonathan Wakely
11个回答

91

Ping根据错误类型返回不同的退出代码。

ping 256.256.256.256 ; echo $?
# 68

ping -c 1 127.0.0.1 ; echo $?
# 0

ping -c 1 192.168.1.5 ; echo $?
# 2

0表示主机可达

2表示不可达


1
很酷...我还是新手脚本编写者,认为我的代码中的if确实检查了退出代码... - burtek
2
它确实会触发echo 1块,只要有任何非0退出代码(所有错误)。但是要弄清楚是什么类型的错误,您需要检查确切的退出代码。 - StianE
3
你第一次尝试得到的是“68”吗?我得到的是“2”,并且是未知主机。在第三个例子中,我得到的是“1”,显示目标主机不可达。 - nephewtom
我在MacOS上看到返回码为68,但在Linux上是2,可能是由于无法解析主机名。此外,在MacOS上(我认为在BSD上也是一样),还有一个-o选项,可以在单个成功数据包后返回。 - Peter B
@StianE 不,OP的命令并不检查成功或失败。它获取由ping打印的文本输出,并检查它是否为空字符串。由于ping无论成功与否都会打印出一些内容,所以它永远不会打印空字符串,因此脚本总是执行echo 1 - Jonathan Wakely

91

在if语句中不需要使用反引号。您可以使用此检查

if ping -c 1 some_ip_here &> /dev/null
then
  echo "success"
else
  echo "error"
fi

if 命令检查下一条命令(ping)的退出代码。如果退出代码为零(这意味着命令成功退出),则执行 then 块。如果它返回非零退出代码,则执行 else 块。


我建议将"&>"替换为">",否则脚本将继续运行。 - TNT
7
这取决于所使用的shell。在bash中,"&> file"等同于"> file 2>&1",即同时重定向标准输出和标准错误输出。 - user000001
我们也可以执行 ping -t 1 -c 1 <ip> 吗? - alper
@alper:当然,这将限制TTL只能到达一个跳点。 - user000001

36
我可以想到一个像这样的一行代码来运行。
ping -c 1 127.0.0.1 &> /dev/null && echo success || echo fail

将127.0.0.1替换为IP地址或主机名,在两种情况下用需要执行的命令替换echo命令。

上面的代码将成功,可以尝试使用您知道无法访问的IP地址或主机名。

像这样:

ping -c 1 google.com &> /dev/null && echo success || echo fail

和这个

ping -c 1 lolcatz.ninja &> /dev/null && echo success || echo fail

3
非常好的一句话!! - Vaclav Kusak

25

有一个名为"fping"的高级ping版本,它可以定义以毫秒为单位的超时时间。

#!/bin/bash
IP='192.168.1.1'
fping -c1 -t300 $IP 2>/dev/null 1>/dev/null
if [ "$?" = 0 ]
then
  echo "Host found"
else
  echo "Host not found"
fi

6
没错,但是单位是秒。fping 的单位是毫秒,如果你需要ping很多台主机,这一点非常重要。 - Fedir RYKHTIK
3
在“类Unix”系统中,ping命令的-t选项不是用于设置超时时间,而是用于设置TTL(生存时间)。超时时间应该使用-W选项来指定。请注意:如果DNS服务器关闭并且需要解析DNS名称,则此操作仍可能会阻塞很长时间。考虑到最近的攻击事件,应该对此进行评估。 - dom0
3
和其他答案一样,这个答案也有反模式 cmd; if [ $? = 0 ]; then ...,更好、更符合惯用法的写法是 if cmd; then ... -- shell 中 if 和其他流程控制语句的目的正是运行一个命令并检查其退出状态。你很少需要直接检查 $? - tripleee
3
这绝对是一种反模式。 - William Pursell
1
请参考 https://www.shellcheck.net/wiki/SC2181 了解为什么首选 if cmd; then ...。同时建议您使用 shellcheck 对脚本进行检查。 - ptha
显示剩余2条评论

11

这是一个完整的bash脚本,每5秒ping一次目标,并将错误记录到文件中。

享受!

#!/bin/bash
        
        FILE=errors.txt
        TARGET=192.168.0.1

          touch $FILE
          while true;
          do
            DATE=$(date '+%d/%m/%Y %H:%M:%S')
            ping -c 1 $TARGET &> /dev/null
            if [[ $? -ne 0 ]]; then
              echo "ERROR "$DATE
              echo $DATE >> $FILE
            else
              echo "OK "$DATE
            fi
              sleep 5
          done

5

提供信息, 我刚刚使用上述方法进行了一些测试,如果我们使用多个ping(10个请求)

ping -c10 8.8.8.8 &> /dev/null ; echo $?

如果至少有一个ping结果可达,则多ping命令的结果将为“0”,如果所有ping请求都无法到达,则结果为“1”。


将输出发送到 /tmp 文件中,通过 lxpanel 等 GUI 进行检查,即可在托盘中获得上/下指示器。或者最近我喜欢使用循环,例如每 30 秒 ping 一次,然后发出响铃字符,并在 ping 成功时退出。也许可以在 Android 手机上使用 Termux。但这不再是一个单行命令了。 - Alan Corey

1
up=`fping -r 1 $1 `
if [ -z "${up}" ]; then
    printf "Host $1 not responding to ping   \n"
    else
    printf "Host $1 responding to ping  \n"
fi

0
for i in `cat Hostlist`
do  
  ping -c1 -w2 $i | grep "PING" | awk '{print $2,$3}'
done

-1

每秒检查主机并在主机可达时发送消息

while :;do ping -c 1 -w 1 -q 8.8.8.8 &>/dev/null && /root/telegram-send.sh "Host reacheble now" && break || sleep 1;done

不过,这并不是OP所要求的。 - Jonathan Wakely

-1

我喜欢检查像这样的列表的想法:

for i in `cat Hostlist`
do  
  ping -c1 -w2 $i | grep "PING" | awk '{print $2,$3}'
done

但是那段代码片段并不关心主机是否无法访问,所以在我看来并不是一个很好的答案。

我接受了它并写下了:

for i in `cat Hostlist`
do
  ping -c1 -w2 $i >/dev/null 2>&1 ; echo $i $?
done

然后我可以分别处理每个。


欢迎来到 Stack Overflow!以后请使用反引号字符(`)而不是句点字符(.)来定义代码块。这将修复您的代码块格式。 - Hoppeduppeanut
我不相信我在代码片段中使用了句号? - bpleat

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接