【问题标题】:Filtering on a condition using the column names and not numbers使用列名而不是数字过滤条件
【发布时间】:2021-10-03 18:19:54
【问题描述】:

我正在尝试根据两个条件过滤包含列的文本文件。由于文件的大小,我不能使用列号(因为有数千个并且没有编号),但需要使用列名。我已经搜索并尝试了多种方法来执行此操作,但没有任何内容返回到命令行。

以下是我尝试过的一些事情:

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=water 的计数)

【问题讨论】:

  • 文件大小与什么有什么关系?
  • 考虑查看how do I ask a good question,然后回来并相应地更新问题;特别是,提供样本输入和(正确的)所需输出
  • 您的列是由制表符或空格分隔还是由任何空格分隔,它们是固定宽度的字段还是什么?

标签: linux awk terminal grep bioinformatics


【解决方案1】:

使用您的输入文件和隐含条件,这应该可以工作

$ 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 

【讨论】:

  • 感谢您的回答。当我运行脚本并更改变量时,我至少得到了回报,但它为零
  • 您是否尝试过您发布的示例输入?用这种方式验证脚本应该很容易。
  • 我做到了,它适用于示例文件,但不适用于实际文件。我会提供数据,但它是非常庞大且敏感的信息。有什么办法可以编写一个脚本来返回给定变量的列号?我试图在上面的问题中做到这一点,但没有成功
【解决方案2】:

正如我在之前的评论中提到的,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'

【讨论】:

    【解决方案3】:

    使用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
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2016-04-21
      • 2021-07-10
      • 1970-01-01
      • 2011-09-15
      • 2019-12-26
      • 2021-08-02
      • 2014-06-28
      • 2023-01-04
      相关资源
      最近更新 更多