如何在Bash中获取Ping收到的数据包百分比?

6
当ping主机时,我希望输出只显示接收到的数据包的百分比(发送了5个)。我认为我需要以某种方式使用grep,但我无法弄清楚如何做到这一点(我是bash编程的新手)。这就是我所在的位置:ping -c 5 -q $host | grep ?。在grep中应该填什么?我认为我需要进行一些算术运算才能获得接收的百分比,但我可以处理这个问题。如何从ping将输出的摘要中提取所需的信息?
6个回答

13
到目前为止,我们已经使用grep、sed、perl、bc和bash得到了一个答案。这里有一种AWK味道的方法,“一种专为文本处理设计的解释性编程语言”。这种方法旨在使用ping观察/捕获实时数据包丢失信息。
要仅查看数据包丢失信息:

命令

$ ping google.com | awk '{ sent=NR-1; received+=/^.*(time=.+ ms).*$/; loss=0; } { if (sent>0) loss=100-((received/sent)*100) } { printf "sent:%d received:%d loss:%d%%\n", sent, received, loss }'

输出

sent:0 received:0 loss:0%
sent:1 received:1 loss:0%
sent:2 received:2 loss:0%
sent:3 received:2 loss:33%
sent:4 received:2 loss:50%
sent:5 received:3 loss:40%
^C

然而,我发现查看原始输入也很有用。为此,您只需在脚本的最后一个块中添加print $0;即可:

命令

$ ping google.com | awk '{ sent=NR-1; received+=/^.*(time=.+ ms).*$/; loss=0; } { if (sent>0) loss=100-((received/sent)*100) } { print $0; printf "sent:%d received:%d loss:%d%%\n", sent, received, loss; }'

输出

PING google.com (173.194.33.104): 56 data bytes
sent:0 received:0 loss:0%
64 bytes from 173.194.33.46: icmp_seq=0 ttl=55 time=18.314 ms
sent:1 received:1 loss:0%
64 bytes from 173.194.33.46: icmp_seq=1 ttl=55 time=31.477 ms
sent:2 received:2 loss:0%
Request timeout for icmp_seq 2
sent:3 received:2 loss:33%
Request timeout for icmp_seq 3
sent:4 received:2 loss:50%
64 bytes from 173.194.33.46: icmp_seq=4 ttl=55 time=20.397 ms
sent:5 received:3 loss:40%
^C

这一切是如何运作的?

您阅读了命令,尝试了一下,它起作用了!那么到底发生了什么?

$ ping google.com | awk '...'

我们首先通过ping google.com并将输出内容管道传输到解释器awk中。单引号中的所有内容定义了脚本的逻辑。
以下是以友好的空格格式呈现的脚本:
# Gather Data
{
  sent=NR-1;
  received+=/^.*(time=.+ ms).*$/;
  loss=0;
}

# Calculate Loss
{
  if (sent>0) loss=100-((received/sent)*100)
}

# Output
{
  print $0; # remove this line if you don't want the original input displayed
  printf "sent:%d received:%d loss:%d%%\n", sent, received, loss;
}

我们可以将其分解成三个组件:
{ gather data } { calculate loss } { output }

每次 ping 输出信息时,AWK 脚本将会消耗它并对其运行此逻辑。

收集数据

{ sent=NR-1; received+=/^.*(time=.+ ms).*$/; loss=0; }

这个例子有三个动作:定义sentreceivedloss变量。
sent=NR-1;

NR是AWK变量,用于表示当前记录数。在AWK中,一条记录对应一行。在我们的例子中,一次ping操作输出的单行即为一条记录。而ping的第一行输出是一个标题,不代表实际的ICMP请求。因此,我们创建一个变量sent,并将其赋值为当前行号减一。

received+=/^.*(time=.+ ms).*$/;

这里我们使用一个正则表达式^.*(time=.+ ms).*$来判断ICMP请求是否成功。由于每个成功的ping都会返回所用时间,因此我们将其作为关键词。
对于那些不太熟悉正则表达式模式的人,这就是我们的意思:
  1. ^从行首开始
  2. .*匹配任何内容直到下一条规则
  3. (time=.+ ms)匹配“time=N ms”,其中N可以是一个或多个任意字符
  4. .*匹配任何内容直到下一条规则
  5. $匹配行尾
当匹配到该模式时,我们会增加变量received的值。

计算丢失率

{ if (sent>0) loss=100-((received/sent)*100) }

现在我们知道发送和接收的ICMP请求数量,我们可以开始进行数学计算以确定数据包丢失情况。为了避免除以零错误,在进行任何计算之前,我们要确保已经发送了请求。计算本身非常简单:
  1. received/sent = 十进制格式下的成功率百分比
  2. *100 = 从十进制转换到整数格式
  3. 100- = 将成功率百分比反转为失败率百分比

输出

{ print $0; printf "sent:%d received:%d loss:%d%%\n", sent, received, loss; }

最后我们只需要打印相关信息。

我不想记住这些

你可以将脚本保存到文件中(例如packet_loss.awk),而不是每次都输入或查找答案。然后,你只需要输入:

$ ping google.com | awk -f packet_loss.awk

11

通常有许多不同的方法可以实现此目标,但这里有一个选项:

这个表达式将从“X% packet loss”中捕获百分比数字。

ping -c 5 -q $host | grep -oP '\d+(?=% packet loss)'
您可以将“损失”百分比从100中减去,以获取“成功”百分比:

然后您可以从100中减去“损失”百分比,得到“成功”百分比:

packet_loss=$(ping -c 5 -q $host | grep -oP '\d+(?=% packet loss)')
echo $[100 - $packet_loss]

3
假设您的ping结果如下所示:
PING host.example (192.168.0.10) 56(84)字节的数据。
--- host.example ping统计 --- 已发送5个包,收到5个包,丢失率0%,时间4000ms rtt最小/平均/最大/mdev = 0.209 / 0.217 / 0.231 / 0.018毫秒
将您的ping -c 5 -q通过管道传输:
grep -E -o '[0-9]+ received' | cut -f1 -d' '

输出结果:

5

然后你可以进行算术运算。


我认为问题是如何同时提取两个数字。 - Roman Byshko
@RomanB:在 ping 命令行中指定了发送的数据包数量。 - MattH

1
echo $((100-$(ping -c 5 -q www.google.hu | sed -rn "/packet loss/ s@.*([0-9]+)%.*@\1@p")))

0

尝试一个脚本:

/bin/bash
rec=ping -c $1 -q $2 | grep -c "$2" | sed -r 's_$_ / \$1_' | xargs expr

保存并使用两个命令行参数运行它。第一个是数据包数量,第二个是主机名。


无法使其正常工作。第一行应该是一个 shebang 吗? - Henno

0

这个对你有用吗?

bc -l <<<100-$(ping -c 5 -q $host |
               grep -o '[0-9]% packet loss' |
               cut -f1 -d% )

它获取ping报告的百分比,并从100中减去它,以得到接收数据包的百分比。


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