linux 使用列名而不是数字对条件进行筛选

pgpifvop  于 2023-02-15  发布在  Linux
关注(0)|答案(4)|浏览(125)

我正尝试根据两个条件筛选包含列的文本文件。由于文件的大小,我无法使用列号(因为有数千列且未编号),但需要使用列名。我已搜索并尝试想出多种方法来完成此操作,但命令行中没有返回任何内容。
以下是我尝试过的几种方法:
awk '($colname1==2 && $colname2==1) { count++ } END { print count }' file.txt,根据列的条件筛选出列
以及head -1 file.txt | tr '\t' | cat -n | grep "COLNAME来尝试并返回与该列相关的可能的列号。
示例文件如下:

ID  ad   bd

1   a   fire
2   b   air
3   c   water
4   c   water
5   d   water
6   c   earth

输出为:2(ad=c和bd=水的计数)

2sbarzqh

2sbarzqh1#

与您的输入文件和隐含条件,这应该工作

$ awk -v c1='ad' -v c2='bd' 'NR==1{n=split($0,h); for(i=1;i<=n;i++) col[h[i]]=i} 
                             $col[c1]=="c" && $col[c2]=="water"{count++} END{print count+0}' file

2

也可以用脚本中的值替换c1和c2。
查找列索引,您可以运行

$ awk -v cols='ad bd' 'BEGIN{n=split(cols,c); for(i=1;i<=n;i++) colmap[c[i]]} 
                       NR==1{for(i=1;i<=NF;i++) if($i in colmap) print $i,i; exit}' file

ad 2
bd 3

或者用这条链子

$ sed 1q file | tr -s ' ' \\n | nl | grep -E 'ad|bd'

     2  ad
     3  bd

尽管可能由于正则表达式匹配而出现假阳性...
您可以重写awk以使其更加简洁

$ awk -v cols='ad bd' '{while(++i<=NF) if(FS cols FS ~ FS $i FS) print $i,i; 
                        exit}' file

ad 2
bd 3
jmo0nnb3

jmo0nnb32#

正如我在前面的评论中提到的,https://unix.stackexchange.com/a/359699/133219的答案显示了如何做到这一点:

awk -F'\t' '
    NR==1 {
        for (i=1; i<=NF; i++) {
            f[$i] = i
        }
    }
    ($(f["ad"]) == "c") && ($(f["bd"]) == "water") { cnt++ }
    END { print cnt+0 }
' file
2

我假设你的输入是制表符分隔的,因为你的问题中的命令中的tr '\t'看起来像是你试图将制表符转换成换行符,将列名转换成数字。如果我错了,它们只是被任何白色链分隔,那么从上面删除-F'\t'

lp0sw83n

lp0sw83n3#

使用miller工具包可以使用列名操作制表符分隔的文件。下面是一行程序,它过滤制表符分隔的文件(分隔符使用--tsv指定),并将结果与标头一起写入STDOUT。标头使用tail删除,行数使用wc计数。

mlr --tsv filter '$ad == "c" && $bd == "water"' file.txt | tail -n +2 | wc -l

图纸:

2
    • 另见:**

miller manual
注意,miller可以很容易地安装,例如,使用conda,如下所示:

conda create --name miller miller
apeeds0o

apeeds0o4#

多年来,我一直在烦恼,Unix中没有简洁的方法来完成这类事情,尽管miller是一个很好的工具。最近,我编写了pick来按名称选择列,并按名称修改、合并和添加它们,以及使用列名按子句过滤行。使用pick解决上述问题的方法是

pick -h @ad=c @bd=water < data.txt | wc -l

默认情况下,pick打印所选列的标题,-h表示忽略它。要打印列,您只需在命令行中命名它们,例如:

pick ad water < data.txt | wc -l

Pick有许多模式,所有这些模式都侧重于用最少的语法操作列和选择/过滤行。

相关问题