【问题标题】:Using Awk with escape characters inside a Bash script在 Bash 脚本中使用带有转义字符的 Awk
【发布时间】:2014-08-01 22:24:30
【问题描述】:

我正在为 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"}'`

我从 packetLost 中返回值并回显它,它给出“0%”,完全忽略了 \b

有人能解释一下为什么在 shell 脚本中会发生这种情况以及我该如何解决这个问题吗?

我了解有其他替代方法,例如使用 cut,但我希望尽可能保持线路简单高效。

【问题讨论】:

  • 终端的shell和脚本的一样吗?
  • 是的,两者都使用 bash
  • 为什么不在 awk 中直接关闭 gsub % 字符,而不是玩打印转义技巧?
  • 试试printf("%s", substr($6, 1, length($6)-1))
  • 我觉得 Awk 是实现我所需要的最干净、最简单的方法。

标签: linux bash shell awk escaping


【解决方案1】:

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

$ ping -q gnu.org -c10 |\
     gawk '{ if (match ($0, /([[:digit:]]+(\.[[:digit:]]+)?)% packet loss/, a)) print a[1]; }'
0

a[1] 这里对应正则表达式中的第一个() 组。

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

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

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

【讨论】:

  • 谢谢!这是一个很好的答案。我对以编程方式使用 ping 的工作并不多,所以我忽略了 quiet 选项。
  • 这只匹配小数点后的数字。例如99.9% packet loss 将匹配 9
  • 如果您担心语言环境,您应该使用[[:digit:]] 而不是[0-9]。另外,不要将条件放在操作部分中,而是将其放在条件部分中:gawk 'match ($0, /([0-9]+)% packet loss/, a) {print a[1]}'.
  • @JohnB 你在哪里读到ping 将百分比四舍五入到十分之一而不是整数。我做了一些测试,得到了这个:145 packets transmitted, 127 received, 12% packet loss, time 144676ms while (145 − 127) / 145 ≈ 12.4 %。
  • @DimitryAlexandrov 在 OS X 上试试这个,你会看到的。
【解决方案2】:

检查下一个:

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

【讨论】:

  • 当我使用函数时,echo 作为返回。这个想法是收集各种数据,最后将其放入一个大格式的字符串中以供输出。我已经尝试过你的建议,但它仍然给出 0%、100% 等。
  • @Kervate 在这种情况下,您需要从输出中删除 %。 (\b 不会删除它 - 正如您在转储中看到的那样。)
【解决方案3】:

awk '{sub(/%/, "", $6); printf $6} 或者 awk '{print substr($6, 1, length($6) - 1)}'

【讨论】:

    猜你喜欢
    • 2019-12-17
    • 1970-01-01
    • 1970-01-01
    • 2019-06-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-07-10
    • 2016-01-01
    相关资源
    最近更新 更多