![Bash - 过滤占据一定比例列的行](https://linux22.com/image/166429/Bash%20-%20%E8%BF%87%E6%BB%A4%E5%8D%A0%E6%8D%AE%E4%B8%80%E5%AE%9A%E6%AF%94%E4%BE%8B%E5%88%97%E7%9A%84%E8%A1%8C.png)
因此,我有大量文件,每个文件有 8 列和很多行。这是其中一个的头部示例。
ID Ct 1 2 3 4 5 6
1 0 consensus - - - - -
2 0 consensus - - - - -
3 0 consensus consensus consensus consensus consensus consensus
4 0 consensus - consensus - - -
5 0 - AT AT GC GC AT
6 0 consensus - - - consensus -
7 0 consensus - - - - -
8 0 consensus consensus consensus - consensus consensus
9 0 consensus - - - - -
我想分离出最后 6 列至少被占用 5/6 的所有行。所以 ID 3、5 和 8(第 4、6 和 9 行)来自我的脑海。所以我希望所有少于 2 列的行都带有“-”,有效。
我曾经能够使用一个简单的 awk 脚本来做到这一点,因为该程序计算了第二列中占用了多少列 - 似乎我不能再这样做了。最好的方法是什么?
答案1
会走多远
awk 'gsub(/-/, "&") < 2' file
ID Ct 1 2 3 4 5 6
3 0 consensus consensus consensus consensus consensus consensus
5 0 - AT AT GC GC AT
8 0 consensus consensus consensus - consensus consensus
我懂了?请注意,rg 没有说什么。所需的输出 - 您想要单个输出文件、以输出行为前缀的文件名,还是名称与原始文件相似的新文件,还是什么?
编辑(在对新文件名进行评论后):
awk 'gsub(/-/, "&") < 2 {print > (FILENAME ".new")}' /path/to/file/*
答案2
如果所有文件都位于同一目录中,则可以使用 for 循环/glob 循环每个文件并对其运行 awk 命令:
for file in /path/to/files/*; do
awk '{
count=0
for (i=3;i<=8;i++) {
if ($i == "-") {
count++
}
}
if ((count <= 1)) {
print
}
}' "$file"
done
对于每一行,它将循环遍历第 3-8 列,如果该列的值等于-
它与 相加的值count
,如果count
一行的值大于 1,则不会打印。
答案3
Perl 对于这种事情很方便 - 特别是,它允许在grep
没有显式循环的情况下按字段进行,其结果(当在标量上下文中评估时)给出匹配的计数。例如
$ perl -lane 'print if 3 > grep { $_ eq "-" } splice @F, 2' file
ID Ct 1 2 3 4 5 6
3 0 consensus consensus consensus consensus consensus consensus
5 0 - AT AT GC GC AT
8 0 consensus consensus consensus - consensus consensus