根据列中字符串匹配的数量删除列

根据列中字符串匹配的数量删除列

我需要一个命令来删除文本文件中的任何列,如果它们在列(具有不同行数的列)中有 =>${MaxAllowedNumberOfFs} 'F。

我有一些接近的伪代码,但我不知道如何设置匹配数限制器。

假设限制器设置为 3,示例输入文件为:

F G F H H
G F F F A
F G F F F
F F F T F

那么期望的输出将是:

G H H
F F A
G F F
F T F

接近的伪代码(限制器可以并且将根据文件而改变):

MaxAllowedNumberOfFs="1012"

Count_of_columns=`awk '{print NF}' filename | sort -nr | sed -n '$p'` 

for((i=1;i<=$Count_of_columns;i++)); do awk -v i="$i" -v x="$MaxAllowedNumberOfFs" '$i == F =>x number of times {$i="";print $0}' filename; done

显然,我可以使用 grep 循环遍历所有列,计算列中出现的次数,然后删除不符合条件的列。但这真的很慢。真的想要一个漂亮的 awk 命令,但我没有 awk 技能

答案1

一种方法是读取文件两次。第一次计算 F,第二次输出该行。所以像

#!/bin/sh

awk -v n=3 '
        NR==FNR { for (i=1;i<=NF;i++) { if ($i == "F") { c[i]++ }} ;next }                                                                            
        { for (i=1;i<=NF;i++) { if (c[i] < n) { printf("%s ", $i) } } ;printf("\n") }                                                                 

' filename filename

NR==FNR是一个技巧来判断这是我们第一次还是第二次读取文件。假设文件中有任何行,那么仅在第一次读取文件时才为真。该数组c是该列中 F 字符数的计数。表示next该行的所有处理在第一次读取文件时已完成。第二行在第二次读取文件时执行。

答案2

这是一个说明转置 - 线路滤波器 - 转置方法。它可能不适合您的(大文件)情况,但可能对其他人有价值:

$ cat file
F G F H H
G F F F A
F G F F F
F F F T F

然后

$ rs -T < file | perl -alne 'print unless (grep { $_ eq "F" } @F) > 3' | rs -T
F  G  H  H
G  F  F  A
F  G  F  F
F  F  T  F

答案3

尝试使用下面的脚本,效果很好

for ((i=1;i<=5;i++)); do c=`awk -v i="$i" '{print $i}' o.txt|awk '$1=="F" {print $0}'| sed -n '/F/{;=;p}'| sed "N;s/\n/ /g"| sort -k1 -rn|sed -n '1p'| awk '{print $1}'`; if [[ $c -lt 3 ]]; then awk -v i="$i" '{print $i}' o.txt >file_$i; fi; done

paste  file_*

输出

G H H
F F A
G F F
F T F

相关内容