【问题标题】:How to filter lines by counting occurences of a char in AWK or bash?如何通过计算 AWK 或 bash 中出现的字符来过滤行?
【发布时间】:2012-10-31 10:54:31
【问题描述】:

输入是这样的:

CNNCC
NCNCN
NNNCC
CCNNN
CCCCN

输出应该是这样的:

CNNCC
CCCCN

这意味着,如果有 N 出现超过 3 次,则该行将被过滤掉,否则将被保留。 (在我的工作中,我需要过滤掉超过 500 N 的 100000 行,因此性能可能很重要)

我知道如何在 awk 中按连续的N 过滤,但我不知道如何计算不连续的..

有人对此有想法吗? shell 中的解决方案也可以。

在所有答案中,我认为这个可能是最简单的:

awk -FN 'NF<=3'

【问题讨论】:

    标签: linux shell sed awk


    【解决方案1】:
    awk -FN -vcount=3 'NF<=count'
    

    或者,对于不支持-v 选项的旧版awk

    awk -FN 'NF<=count' count=3
    

    该命令使用目标字符作为字段分隔符,最大允许出现次数为count。通过将生成的字段数与count 进行比较,我们可以选择性地打印符合我们标准的行。

    该语句的意图不是很明显,因此可读性较差。但是,它确实具有将 char 和 count 参数化的优点,因此可以轻松地重复用于不同的设置。

    诚然,这对于大量count 来说效率不高。将最大字段数设置为count+1 可以解决这个性能问题,不幸的是,gawk 忽略了-mf 选项。

    【讨论】:

    • 这个作品!但仅适用于 gawk 它在我的 MACOS 上显示 /usr/bin/awk: invalid -v option
    • @Firegun 如果您愿意硬编码count,请尝试awk -F'N' 'NF&lt;=3{print}'
    • 不使用-v,还可以使用:awk -FN 'NF&lt;=count' count=3。 ({print} 是多余的。)
    • 如果您的 awk 不支持 -v 则获得一个新的 awk,因为所有现代 awk 都支持该选项,而不仅仅是 GNU awk,任何不支持该选项的 awk 都会丢失其他功能也。此外,-v 通常是设置变量的正确方法,因为它也为 BEGIN 部​​分设置它们,而在 arg 列表中使用 var=val 仅在 BEGIN 之后设置它们。不错的解决方案 +1!
    • 很好,但我建议您不要将命令命名为“gawk”,因为这听起来像是它不是特定于 gawk 的:-v 将​​适用于所有现代 awk,包括 gawk, nawk、tawk、/usr/xpg4/bin/awk 等
    【解决方案2】:

    这可能对你有用(GNU sed):

    sed -r '/(.*N){3}/d' file
    

    sed 's/N/&/3;T;d' file
    

    【讨论】:

      【解决方案3】:

      使用相同正则表达式的sed解决方案:

      % sed '/N.*N.*N/d'
      

      d 删除 anywhere 包含三个或更多 N 字符的每一行。

      示例:

      % sed '/N.*N.*N/d' <<EOF
      `heredoc> CNNCC
      `heredoc> NCNCN
      `heredoc> NNNCC
      `heredoc> CCNNN
      `heredoc> CCCCN
      `heredoc> EOF
      CNNCC
      CCCCN
      

      【讨论】:

        【解决方案4】:

        你可以使用gsub来计数:

        awk 'gsub(/N/,"N") < 3' file.txt
        

        结果:

        CNNCC
        CCCCN
        

        【讨论】:

        • 但这会gsub 每个 N。在第三个N之后停止匹配还不够吗?
        【解决方案5】:

        不喜欢grep

        count=3
        egrep -v "(.*N){$count}" file
        

        更多信息:

        -v 反转匹配,因此这会查找不包含 3 个 N 的行(如果该行有超过 3 个 N,则它包含 3 个 N)。

        egrep 等价于使用扩展正则表达式 (ERE) 的grep -E,在此处使用这样( ){ } 就不必转义。

        【讨论】:

          【解决方案6】:

          Perl 单行

          perl -ne 'print if tr/N/N/ < 3'
          

          【讨论】:

            【解决方案7】:

            这样就可以了:

            gawk '/N.*N.*N/ { next; } { print; }'
            

            【讨论】:

            • @Firegun 行数不相关。 gawk 的正则表达式实现应该足够高效,可以匹配包含 500+ 个字符的偶数行。
            猜你喜欢
            • 1970-01-01
            • 2022-06-11
            • 2018-01-07
            • 2021-07-04
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2016-07-09
            相关资源
            最近更新 更多