根据 =0.00000000 的列数过滤文件的行

根据 =0.00000000 的列数过滤文件的行

我想根据第 5 列之后的列数来过滤文件(例如下面的 file.txt)的行=0.00000000

下面的 I/O 显示了一个示例过滤具有 1 列以上(第 5 列之后)且值为零的行,或者=0.00000000(换句话说,删除具有两列或更多零值列的行,或删除具有非零值的少于 6 列(第 5 列之后)的行)。

有没有一种方法可以灵活地执行此操作,以便我可以决定过滤具有超过 1 或 2 或 3 列(第 5 列之后)的行=0.00000000

真实的文件有数千行和 61 或 71 列,尽管前 5 列是相同的。

文件.txt

MT 227 1 1.000 42.0 1:2=0.00036000 1:3=0.00000000 1:4=0.00004200 1:5=0.04300000 1:6=0.03400000 1:7=0.00000000 1:8=0.01204819
MT 233 1 1.000 60.0 1:2=0.10000000 1:3=0.00639386 1:4=0.00000000 1:5=0.00584795 1:6=0.20040000 1:7=0.10030000 1:8=0.02300000
MT 245 1 1.000 107.0 1:2=0.02000000 1:3=0.05600000 1:4=0.00000000 1:5=0.00000000 1:6=0.00000000 1:7=0.02922158 1:8=0.12631579
MT 251 1 1.000 136.0 1:2=0.13384412 1:3=0.01738004 1:4=0.10528891 1:5=0.00070562 1:6=0.01081160 1:7=0.00697347 1:8=0.00453430
MT 264 1 1.000 207.0 1:2=0.00000000 1:3=0.00000000 1:4=0.00000000 1:5=0.00413223 1:6=0.00000000 1:7=0.00192377 1:8=0.00000000
MT 286 1 1.000 300.0 1:2=0.00157816 1:3=0.00126087 1:4=0.00124224 1:5=0.00144928 1:6=0.00209524 1:7=0.00124224 1:8=0.00197719
MT 292 1 1.000 337.0 1:2=0.02000000 1:3=0.30000000 1:4=0.04000000 1:5=0.00050000 1:6=0.00148588 1:7=0.00000000 1:8=0.04000000
MT 293 1 1.000 326.0 1:2=0.00000000 1:3=0.00000000 1:4=0.00000000 1:5=0.00000000 1:6=0.00153610 1:7=0.00113162 1:8=0.00000000
MT 295 1 1.000 333.0 1:2=0.00084409 1:3=0.00125321 1:4=0.00117912 1:5=0.00067806 1:6=0.00041798 1:7=0.00108578 1:8=0.00183284
MT 296 1 1.000 343.0 1:2=0.00000000 1:3=0.00000000 1:4=0.00000000 1:5=0.00233645 1:6=0.00000000 1:7=0.00108070 1:8=0.00144300

输出.txt

MT 233 1 1.000 60.0 1:2=0.10000000 1:3=0.00639386 1:4=0.00000000 1:5=0.00584795 1:6=0.20040000 1:7=0.10030000 1:8=0.02300000
MT 251 1 1.000 136.0 1:2=0.13384412 1:3=0.01738004 1:4=0.10528891 1:5=0.00070562 1:6=0.01081160 1:7=0.00697347 1:8=0.00453430
MT 286 1 1.000 300.0 1:2=0.00157816 1:3=0.00126087 1:4=0.00124224 1:5=0.00144928 1:6=0.00209524 1:7=0.00124224 1:8=0.00197719
MT 292 1 1.000 337.0 1:2=0.02000000 1:3=0.30000000 1:4=0.04000000 1:5=0.00050000 1:6=0.00148588 1:7=0.00000000 1:8=0.04000000
MT 295 1 1.000 333.0 1:2=0.00084409 1:3=0.00125321 1:4=0.00117912 1:5=0.00067806 1:6=0.00041798 1:7=0.00108578 1:8=0.00183284

=0.00000000删除具有using 的列(第 5 列之后)的任何行会容易得多,grep -v "=0.00000000"但这会丢弃太多数据。任何帮助是极大的赞赏!

答案1

我能找到的最简单的解决方案是(是的,就是这么简单):

awk -F '=0\\.00000000'   'NF<=2'   file

对此有几种可能的解决方案。

  1. grep查找文本的速度相当快,它只需要正确的正则表达式。

    grep -vE '^([^ ]* ){5}.*(=0\.00000000.*){2}' file
    
    • ^([^ ]* ){5}部分将从一行的开头 ( ) 开始匹配由空格({5}其中 5 ( ) 个)分隔的^列(不是空格)。
    • 然后,.*(=0\.00000000.*){2}将匹配该行上的至少两个=0\.00000000
    • 最后,反转匹配 ( -v) 并使用扩展 (ERE) 正则表达式(较少\需要)。

0它将严格限制要匹配的 s数量。

  1. Sed 具有类似的正则表达式:

    sed '/^\([^ ]* \)\{5\}.*\(=0\.00000000.*\)\{2\}/d' file
    

    但它会打印任何与模式不匹配的行(很容易失败)。

或者

  1. awk 将这一行视为文本。

    awk -F '=0\\.00000000' 'NF<=2' file
    
  2. awk,它可以解析浮点数,然后检查0值。

    请使用@GlennJackman 的答案。

答案2

使用空格或=作为字段分隔符,从第 7 列开始计算零值:如果有多个值,则继续到下一行,否则打印该行。

awk -F '[= ]+' '{
    z = 0
    for (c = 7; c <= NF; c += 2)
        if ($c == 0.0 && ++z > 1)
            next
    print
}' file

答案3

这是打印不包含多个该字符串实例的行的最简单方法:

grep -v '=0\.00000000.*0\.00000000' file.txt

由于您的文件仅在第 5 列之后出现该字符串,并且您只想打印它出现一次或根本不出现的行,因此上面的代码将打印它不出现多次的行。该模式=0\.00000000.*0\.00000000匹配一​​行上的任意两个实例,=0.00000000无论它们出现在哪一列中,并且如果一行上的任何位置有第三个、第四个、第五个等,则不会打印该行。您尝试的命令会打印不包含该字符串的任何实例的任何行,因此它不会打印您不想要的第二行。

如果您希望它打印不包含该字符串的更多实例的行,只需添加另一个.*0.00000000.例如,要打印不超过三行的行:

grep -v '=0\.00000000.*0\.00000000.*0\.00000000' file.txt

这将包括第三行,其中包含该字符串的三个实例。

相关内容