Linux 在Bash脚本中使用带有转义字符的Awk

Linux 在Bash脚本中使用带有转义字符的Awk,linux,bash,shell,awk,escaping,Linux,Bash,Shell,Awk,Escaping,我正在为Linux系统编写一个shell脚本(使用Bash) 作为这个脚本的一部分,我使用awk获取ping请求丢弃的数据包的百分比。当从如下所示的终端执行时,该操作可以正常工作: test=`ping gnu.org -c10 | tail -2`; echo $test | awk '{printf $6 "\b"}' 这将获取丢弃的数据包的百分比,并使用退格转义字符对其进行回显,以仅显示“0”,而不是“0%”-这是因为该值稍后用作整数值 在脚本中,代码如下所示: #Pings the g

我正在为Linux系统编写一个shell脚本(使用Bash)

作为这个脚本的一部分,我使用awk获取ping请求丢弃的数据包的百分比。当从如下所示的终端执行时,该操作可以正常工作:

test=`ping gnu.org -c10 | tail -2`; echo $test | awk '{printf $6 "\b"}'
这将获取丢弃的数据包的百分比,并使用退格转义字符对其进行回显,以仅显示“0”,而不是“0%”-这是因为该值稍后用作整数值

在脚本中,代码如下所示:

#Pings the gateway ten times and stores the result
local pingResults=`ping -c10 $gateway | tail -2`

#Uses awk to get the percentage of packets lost using \b to remove the %
local packetsLost=`echo $pingResults | awk '{printf $6 "\b"}'`
我从packetsLost返回值并回显它,它给出“0%”,完全忽略\b

有人能解释一下为什么在shell脚本中会发生这种情况,以及我如何补救这种情况吗

我知道还有其他选择,例如使用cut,但我希望线路尽可能简单高效。

检查下一步:

echo 1x 2x 3x 4x 5x 6x 7x | awk '{printf $6 "\b"}' | od -cb
您将获得下一个输出:

0000000    6   x  \b                                                    
          066 170 010      
所以,当你运行

echo 1x 2x 3x 4x 5x 6x 7x | awk '{printf $6 "\b"}'
你被打印出来了:

  • 字符6
  • 字符x
  • 字符退格(是什么导致在终端中删除字符)
现在运行:

aaa=$(echo 1x 2x 3x 4x 5x 6x 7x | awk '{printf $6 "\b"}')
将结果存储到
aaa
,并显示其内容:

echo $aaa | od -bc

0000000   066 170 010 012                                                
           6   x  \b  \n                                                
如果需要相同的结果,请使用:

echo -n $aaa
总之,使用:

local packetsLost=`echo $pingResults | awk '{printf $6 "\b"}'`
echo -n $packetLost
awk'{sub(/%/,“”,$6);printf$6}

awk'{print substr($6,1,length($6)-1)}

OMG!基于单词计数解析人类可读字符串是完全不可维护的(“只写”)和不可预测的。尽量避免。其实很简单:

$ ping -q gnu.org -c10 |\
     gawk '{ if (match ($0, /([[:digit:]]+(\.[[:digit:]]+)?)% packet loss/, a)) print a[1]; }'
0
a[1]
此处对应于regexp中的第一个
()

另外,当您解析人类可读的输出时,有必要确保语言环境(即语言)与您在编写脚本时预期的相同,因此在实际代码中,ping调用应该如下所示:

local pingResults=$(LANG=C ping -q -c10 "$gateway")

(即使看起来,
iputils ping
特别没有任何翻译。)

终端的外壳和脚本的外壳一样吗?是的,bash不仅用于
gsub
在awk中去掉
%
字符,而不是玩打印转义技巧?试试
printf(%s),substr($6,1,length($6)-1))
。我觉得Awk是实现我所需要的最干净、最简单的方法。在我使用函数时,echo起着返回的作用。其思想是收集各种数据,最后将其放入一个大的格式化字符串中进行输出。我已经尝试了您的建议,但它仍然提供0%、100%等。在这种情况下,您需要从输出中删除
%
。(您可以在转储中看到,
\b
不会删除它。)谢谢!这是一个很好的答案。我没有在程序上使用ping,所以我忽略了quiet选项。它只匹配小数点后的数字。e、 g.
99.9%的数据包丢失
将与
9
相匹配。如果您关心区域设置,则应使用
[[:digit:]
而不是
[0-9]
。另外,不要将条件放在操作部分中,只需将其放在条件部分:
gawk'match($0,/([0-9]+)%packet loss/,a){print a[1]}
@JohnB您在哪里读到的
ping
将百分比舍入到十分之一,而不是整数。我做了一些测试,得到了如下结果:
145个数据包传输,127个接收,12%的数据包丢失,时间144676ms
while(145− 127) / 145 ≈ 12.4%。@DimitryAlexandrov在OSX上试试这个,你会看到的。