【问题标题】:How to extract specific data from grep command in bash?如何从 bash 中的 grep 命令中提取特定数据?
【发布时间】:2020-09-22 20:14:19
【问题描述】:

我正在尝试编写自己的脚本来告诉我是否使用了超过 500 MiB 的数据。 我正在使用 vnstat -d 获取有关数据使用的信息。 vnstat -dOutput here

输出应该是:

  1. 仅来自“总计列”
  2. 只有大于 500 的值。

我只想要“总计”列中的值。我的输出列出了所有列的数据。 最好从以下几点清楚:

#!/bin/bash
for i in `vnstat -d | grep -a [0-9] `; //get numerical values in i (-a tag as vnstat outputs in binary)
do 
    NUMBER=$(echo $i | grep -o '[5-9][0-9][0-9]'); //store values >500 in a var called NUMBER
    echo $NUMBER;
done;

我是一个自学新手,所以请尽量不要抨击(双关语)我。

我从上述脚本收到的当前输出:

600
654
925
884
923
871
967
868

我想要的输出应该是:

654   
923    
967

【问题讨论】:

  • Please don't post images of text。这里的人认为这是邪恶的。
  • output_cmd | awk -F\| '{print $3} 可以帮助您入门。阅读awk tutorial。祝你好运。
  • @Typedragon33 : 为什么要排除 600?毕竟,600 > 500!
  • @user1934428 条目 600 不是来自 total 列。
  • 正确,但在您的代码中,您执行 grep -o '[5-9][0-9][0-9]',它搜索行中的 所有 个数字,而不仅仅是标题为 total 的列中的数字i>.

标签: bash shell terminal grep


【解决方案1】:

简化:

#/bin/bash
if [[ $(( $(vnstat -d --oneline|cut -d';' -f6|cut -d. -f1|paste -sd '+') )) -ge 500 ]];then
  echo 500 Mb reached
fi

(脚本的作用是从每个接口的类似 CSV 的单行输出中获取指定字段,然后对整数进行求和。然后比较该总和是否等于或大于500。如果是,then 它会输出一条消息)

注意:

-f6 将解析“今天的总流量”

您可以将其替换为:

-f4 = 今天的 rx

-f5 = 今天的交易

【讨论】:

  • 哇这真的有效!这是天才@Ron。我还是新手,什么都不懂。但是哇,伙计。
  • 你当然可以调整输出或echo,也可以查看man vnstat中的--oneline格式以获得更多输出选项..
【解决方案2】:

您想解析一个以管道分隔的表并仅检查特定列,有比grep 更适合此工作的工具,例如,您可以编写一个小的 bash 脚本,在其中使用cut 命令提取数据并处理它们,或awk

这是awk 的解决方案。我们打印该列的编号> 500total。将您的命令输出发送到

awk -F "|" '($3+0>=500){print $3}'
  • -F 将字段分隔符设置为 |
  • $3+0 用于将以数字开头的字符串转换为该数字,以便 我们可以将其作为数字处理并进行比较。


现在,如果您真的想提取所有具有列total > 500 MiB 的值, 那么预期的输出应该包括所有以GiB 表示的值,因为它们是 > 1000 MiB,例如你的邪恶截图中的最小值是 0.98 GiB,即 1003 MiB。所以我们可以将它添加到第一个条件中。
awk -F "|" '($3 ~ /GiB/ || $3+0>500){print $3}'


现在,如果您希望输出仅是 MiB 中的整数,我们可以将其修改为:
awk -F "|" '($3 ~ /GiB/){$3=1024*$3+0} ($3+0>500){printf "%.0f\n",$3}'

这里我们将所有 GiB 值转换为 MiB,然后进行比较。

【讨论】:

  • 感谢您如此详尽而亲切的解释!我会一步一步来,练完再回来awk
【解决方案3】:

我会使用awk。类似(未经测试)

vnstat -d | awk '$1 == "estimated" { exit }
                 ($9 == "GiB" && $8 > 0.5) ||
                 ($9 == "MiB" && $8 > 500) { print $8 " " $9 }'

【讨论】:

    【解决方案4】:
    #!/bin/bash
    IFS=$'\n'
    for i in `vnstat -d`; do # get each lines
      VALUE=$(echo $i | cut -d\| -f3) # get total value with unit, in case you want to check for GiB values
      NUMBER=$(echo $VALUE | grep -o '[0-9.*]' | cut -d. -f1); # split the string by '|', get the number part, store the integer part into NUMBER
      if [[ $NUMBER -ge 500 && "$VALUE" == *"MiB"* || "$VALUE" == *"GiB"* ]]; then # if the number is greater than or equals to 500 OR it's in GiB
        echo $VALUE; # echo the value
      fi
    done
    

    当然,如果你愿意,你可以去掉 GiB 检查。

    编辑:在开头添加 IFS=$'\n'。这允许 for 循环使用 endline 作为分隔符。

    【讨论】:

    • for 循环处理每个单词,而不是每一行。
    • 不工作。这是我得到的输出。难道我做错了什么?这是我得到的输出textuploader.com/1mghl
    • 糟糕。我在 for 和 for 循环中添加了一行以遍历每一行
    【解决方案5】:

    vnstat 有几个选项来格式化输出。 您可以使用vnstat --dumpdbvnstat --jsonvnstat --xml 来获得格式良好的数据,然后您可以更轻松地解析(例如,如果您选择JSON 格式,则使用jq)。

    例如:

    vnstat --json | jq '.interfaces[] | select(.id == "eth0") | .traffic | .days[1] | .rx'
    

    将提取接口eth0昨天收到的kiB数量(0是今天,1是昨天,等等)

    要获得总rx+tx,可以使用

    vnstat --json | jq '.interfaces[] | select(.id == "eth0") | .traffic | .total | .rx+.tx'
    

    您也可以总结几天,例如今天和昨天:

    vnstat --json | jq '.interfaces[] | select(.id == "eth0") | .traffic | [.days[0,1] | .rx+.tx] | add'
    

    您可以引用“月”或“小时”而不是天(对于hours,请注意,id 的含义不同,它是小时的引用)。

    【讨论】:

      猜你喜欢
      • 2016-11-15
      • 2013-03-19
      • 2019-10-18
      • 2014-06-11
      • 2017-10-18
      • 2021-06-02
      • 2021-10-30
      • 2017-05-06
      • 1970-01-01
      相关资源
      最近更新 更多