![根据 =0.00000000 的列数过滤文件的行](https://linux22.com/image/173027/%E6%A0%B9%E6%8D%AE%20%3D0.00000000%20%E7%9A%84%E5%88%97%E6%95%B0%E8%BF%87%E6%BB%A4%E6%96%87%E4%BB%B6%E7%9A%84%E8%A1%8C.png)
我想根据第 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
对此有几种可能的解决方案。
grep
查找文本的速度相当快,它只需要正确的正则表达式。grep -vE '^([^ ]* ){5}.*(=0\.00000000.*){2}' file
- 该
^([^ ]* ){5}
部分将从一行的开头 ( ) 开始匹配由空格({5}
其中 5 ( ) 个)分隔的^
列(不是空格)。 - 然后,
.*(=0\.00000000.*){2}
将匹配该行上的至少两个=0\.00000000
。 - 最后,反转匹配 (
-v
) 并使用扩展 (ERE) 正则表达式(较少\
需要)。
- 该
0
它将严格限制要匹配的 s数量。
Sed 具有类似的正则表达式:
sed '/^\([^ ]* \)\{5\}.*\(=0\.00000000.*\)\{2\}/d' file
但它会打印任何与模式不匹配的行(很容易失败)。
或者
awk 将这一行视为文本。
awk -F '=0\\.00000000' 'NF<=2' file
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
这将包括第三行,其中包含该字符串的三个实例。