【问题标题】:how to collect maximum and minimum values from a grep search pattern using bash?如何使用 bash 从 grep 搜索模式中收集最大值和最小值?
【发布时间】:2021-04-15 07:19:43
【问题描述】:

我有一个巨大的 log.txt 文件,我需要从中计算最大值和最小值。

 0-00:42:35.598 <tc_testcase>:[DEFAULT]:[PRINT]: tc_testcase.c:8963: VERIFY_CASE: range: X_PER_Y_USER_RANGE_0[1](a, 1)=121, (0)=0, (25000)=25000, (ok)
 0-00:42:35.598 <tc_testcase>:[DEFAULT]:[PRINT]: tc_testcase.c:8963: VERIFY_CASE: range: X_PER_Y_USER_RANGE_0[1](a, 1)=256879, (0)=0, (25000)=25000, (ok)
 0-00:42:35.598 <tc_testcase>:[DEFAULT]:[PRINT]: tc_testcase.c:8963: VERIFY_CASE: range: X_PER_Y_USER_RANGE_0[1](a, 1)=2300, (0)=0, (25000)=25000, (ok)
 0-00:42:35.598 <tc_testcase>:[DEFAULT]:[PRINT]: tc_testcase.c:8963: VERIFY_CASE: range: X_PER_Y_USER_RANGE_0[1](a, 1)=56897132, (0)=0, (25000)=25000, (ok)
 0-00:42:35.598 <tc_testcase>:[DEFAULT]:[PRINT]: tc_testcase.c:8963: VERIFY_CASE: range: X_PER_Y_USER_RANGE_0[1](a, 1)=12579, (0)=0, (25000)=25000, (ok)
 0-00:42:35.598 <tc_testcase>:[DEFAULT]:[PRINT]: tc_testcase.c:8963: VERIFY_CASE: range: X_PER_Y_USER_RANGE_0[1](a, 1)=968746, (0)=0, (25000)=25000, (ok)

所以,作为第一步,我开始使用以下 grep 命令将以下行收集到一个单独的文件中,然后对其进行排序:

 grep -Po '.X_PER_Y_USER_RANGE_0.*[1].*(a, 1).\K.*' file.txt > collect.txt

但我收到的输出完全不同。它看起来像这样:-

=121, (25000)=25000, (ok)
=256879, (25000)=25000, (ok)
=2300, (25000)=25000, (ok)
=56897132, (25000)=25000, (ok)
=12579, (25000)=25000, (ok)
=968746, (25000)=25000, (ok)

预期应该是:-

121
256879
2300
56897132
12579
968746

任何人都可以帮助修改我用来收集值作为预期输出的当前 grep 命令

【问题讨论】:

    标签: bash grep


    【解决方案1】:

    你很接近,试图在这里修复 OP 的尝试。这可以在 GNU grep 中完成,如下所示。我们可以使用 GNU grep-P 选项在此处启用 PCRE 正则表达式。

    grep -oP '.*range: X_PER_Y_USER_RANGE_0\[1\]\([a-zA-Z]+, \d+\)=\K\d+'  Input_file
    

    解释: 简单的解释是,首先启用 GNU grep-oP 选项以启用 PCRE 正则表达式功能并仅获取匹配的值。然后在 grep 的主程序中,使用正则表达式 .*range: X_PER_Y_USER_RANGE_0\[1\]\([a-zA-Z]+, \d+\)= 匹配从开始到直到 () 的所有内容,注意此处转义部分 []() 以使这些字符成为文字字符。然后使用\K 选项忘记所有匹配的值直到现在。提及 \d+ 将匹配其后的数字,这是 OP 获取数字的实际要求。

    【讨论】:

      【解决方案2】:

      您只需要转义特殊的正则表达式字符:

      grep -Po 'range: X_PER_Y_USER_RANGE_0\[1\]\(a, \d\)=\K\d+' file.txt
      121
      256879
      2300
      56897132
      12579
      968746
      

      对于这种情况(对我而言Perl 本身更可取:

      perl -lne '/ \d\)=\K\d+/ && print $&' file.txt
      121
      256879
      2300
      56897132
      12579
      968746
      

      对于 minma​​x 是这样的:

      perl -lne '/ \d\)=\K\d+/g && push(@number,$&); END{ print "@{[sort {$a <=> $b} @number]}[0,-1]"}' file.txt
      121 56897132
      

      and END { ... } 表示排序它们并取出@number数组的0last索引

      对于 sort 使用 而不是 Perl 具有 minma​​x 您可以将输出通过管道传输到:

      ... | { mapfile -t arr; paste <(sort -n <(tr ' ' '\n' <<<  ${arr[@]})) <(sort -rn <(tr ' ' '\n' <<<  ${arr[@]})); }
      121 56897132
      2300    968746
      12579   256879
      256879  12579
      968746  2300
      56897132    121
      

      创建一个数组,然后sort 两次。然后将其发送到head -n 1,例如

      ... | head -n 1
      121 56897132
      

      【讨论】:

      • 它有效。谢谢它的工作原理。我正在使用类似这样的东西对grep -Po 'range: X_PER_Y_USER_RANGE_0\[1\]\(a, \d\)=\K\d+' file.txt | sort -hr | sed -n '1p;$p进行排序但通常会问grep中“。*”和“\”用法有什么区别?
      • 这个.* 是一个贪婪匹配,这意味着尽可能匹配。反斜杠仅用于转义特殊字符,例如(a, 1) 这里 () 是特殊的,既然你想在你的内容中匹配它们,你应该 escape 使用 ``
      猜你喜欢
      • 2014-11-03
      • 2013-04-09
      • 1970-01-01
      • 2014-01-12
      • 2018-12-23
      • 2019-08-18
      • 2018-04-09
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多