通过在Bash脚本中使用ping检查主机可用性


68

我想编写一个脚本,该脚本将不断检查网络中应该整天处于联机状态的设备是否真正处于联机状态。我尝试使用ping,但是

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

给人1不管我输入有效或无效的IP地址。我如何检查特定地址(或更好的IP地址列表中的任何设备)是否离线?


1
您应该考虑使用nmap,它允许您指定IP地址范围。
devnull

FWIW,您的代码段对我来说效果很好。
Torsten Bronger 2015年

不是问题的答案,但您最好使用“ $(ping -c 1 some_ip_here)”而不是“ ping -c 1 some_ip_here”。请参阅此链接以获取更多信息
Sumudu '16

Answers:


67

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
确实如此,您的if将echo 1在任何非0的退出代码(所有错误)上触发该块。但是要弄清楚是哪种错误,您将检查确切的退出代码。
StianE

3
68第一次上吗?我知道2主机。我1在第三个示例中遇到了“无法到达目标主机”。
nephewtom

我在MacOS上看到返回码68,但是在Linux上返回2表示主机名无法解析。在MacOS上也有-o选项(我也假设在BSD中),该选项在单个成功的数据包之后返回。
彼得B

58

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

if ping -c 1 some_ip_here &> /dev/null
then
  echo 1
else
  echo 0
fi

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


我建议用“>”替换“&>”,否则脚本将继续运行。
TNT

2
@TNT取决于外壳。在bash&> file中等效于> file 2>&1,即重定向标准输出和标准错误。
user000001

24

有ping的高级版本-“ fping”,它使以毫秒为单位定义超时成为可能。

#!/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

1
ping还具有-t选项,可用于定义超时。
蒂姆·迪尔伯恩

6
真正。但是几秒钟。fping-以毫秒为单位,如果您要ping的主机很多,那很重要。
Fedir RYKHTIK 2014年

1
在“ unixy”中,ping-t不是用于超时,而是用于TTL。超时是通过-W指定的。注意:例如,它仍然可以长时间阻止。如果DNS服务器消失并且必须解析DNS名称。考虑到最近的攻击,应该考虑这一点。
dom0

1
像这里的许多其他答案一样,此命令具有cmd; if [ $? = 0 ]; then ...更好的反模式,而且更惯用if cmd; then ...,它的用途if以及外壳中的其他流控制语句恰好是运行命令并检查其退出状态。您很少需要$?直接检查。
人间

1
我不会说这是一种反模式,这更多是个人选择的问题。对于我来说,独立行中的命令更易读。
Fedir RYKHTIK

21

我可以想到这样的一个班轮

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

2
很好的一个班轮!!
瓦茨拉夫·库萨克

4

仅供参考,我只是使用上述方法进行了一些测试,如果我们使用多次Ping(10个请求)

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

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


将输出发送到/ tmp中的文件,通过lxpanel之类的GUI进行检查,然后托盘上有一个向上/向下指示器。或者最近我进入了像每30秒执行一次ping的循环,然后发出铃声并在ping成功后退出。也许可以在Android手机上使用Termux。不过,它不再是单线的了。
艾伦·科里

2
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

2

这是一个完整的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

0

在终端仿真器窗口中,这似乎工作得很好。循环直到建立连接,然后停止。

#!/bin/bash

# ping in a loop until the net is up

declare -i s=0
declare -i m=0
while ! ping -c1 -w2 8.8.8.8 &> /dev/null ;
do
  echo "down" $m:$s
  sleep 10
  s=s+10
  if test $s -ge 60; then
    s=0
    m=m+1;
  fi
done
echo -e "--------->>  UP! (connect a speaker) <<--------" \\a

末尾的\ a试图在连接上获取bel char。我一直在尝试在LXDE / lxpanel中执行此操作,但是一切都停止了,直到再次建立网络连接为止。时间是作为进度指示器开始的,因为如果您看着每行都只有“向下”的窗口,您甚至无法说出它在移动。


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

0

我喜欢检查列表的想法,例如:

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
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.