匹配模式并使用awk或grep打印文件中的相应列

时间:2016-08-21 13:47:34

标签: bash awk sed grep

我有一个带有重复标题的输入文件(如下所示):

A1BG A1BG A1CF A1CF A2ML1
aa bb cc dd ee
1 2 3 4 5

我想在一个文件中打印具有相同标题的所有列。例如,对于上面的文件,应该有三个输出文件; 1个A1BG,2列; A1CF第2列,2列; A2ML1的第3列,1列。我有没有办法用awk或grep使用单行?

我试过跟随单行:

awk -v f="A1BG" '!o{for(x=1;x<=NF;x++)if($x==f){o=1;next}}o{print $x}' trial.txt

但是这只在一列中搜索模式(在这种情况下为1)。我想查看所有标题名称并打印其标题中包含A1BG的所有相应列。

6 个答案:

答案 0 :(得分:1)

我无法帮助你使用1-liner,但这里有一个10-liner for GNU awk:

<强> script.awk

  NR == 1 { PROCINFO["sorted_in"] = "@ind_num_asc"
            for( i=1; i<=NF; i++ ) { f2c[$i] = (i==1)? i : f2c[$i] " " i } }
        { for( n in f2c ) { 
              split( f2c[n], fls, " ")
              tmp = ""
              for( f in fls ) tmp = (f ==1) ? $fls[f] : tmp "\t" $fls[f]
              print tmp > n
          }
        }

像这样使用:awk -f script.awk your_file

在第一个操作中:它确定第一个记录(NR == 1)中列的文件名。

在第二个操作中:对于每个记录:对于每个输出文件:其列(在第一个记录中定义)被收集到tmp并写入输出文件。

使用PROCINFO需要GNU awk,请参阅Ed Mortons对备选方案的评论。

示例运行和输出:

> awk -f mpapccfaf.awk mpapccfaf.csv 
> cat A1BG 
A1BG    A1BG
aa      bb
1       2

答案 1 :(得分:1)

awk解决方案应该非常快 - 输出文件以制表符分隔并命名为cols.A1BG cols.A1CF等

awk '
# fill cols columns map to header and tab map to track tab state per header
NR==1 {
  for(i=1; i<=NF; ++i) {
    cols[i]=$i
    tab[$i]=0
  }
}
{
# reset tab state for every header
  for(h in tab) tab[h]=0
# write tab-delimited column to its cols.header file
  for(i=1; i<=NF; ++i) {
    hdr=cols[i]
    of="cols." hdr
    if(tab[hdr]) {
      printf("\t") >of
    } else
      tab[hdr]=1
    printf("%s", $i) >of
  }
# newline for every header file
  for(h in tab) {
    of="cols." h
    printf("\n") >of
  }
}
'

这是我的两个awk解决方案的输出:

$ ./scr.sh <in.txt; head cols.*
==> cols.A1BG <==
A1BG    A1BG
aa      bb
1       2

==> cols.A1CF <==
A1CF    A1CF
cc      dd
3       4

==> cols.A2ML1 <==
A2ML1
ee
5

答案 2 :(得分:1)

这个awk解决方案采用与Lars相同的方法,但使用gawk 4.0 2D阵列

ComboBox

答案 3 :(得分:0)

在这里,根据要求提出单行:

awk 'NR==1{for(i=1;i<=NF;i++)a[$i][i]}{PROCINFO["sorted_in"]="@ind_num_asc";for(n in a){c=0;for(f in a[n])printf"%s%s",(c++?OFS:""),$f>n;print"">n}}' file

以上使用GNU awk 4. *表示真正的多维数组和sorted_in。

对于其他阅读此内容的人而言,他们更倾向于明确OP需要的简洁性,这里它是一个更自然的多行脚本:

$ cat tst.awk
NR==1 {
    for (i=1; i<=NF; i++) {
        names2fldNrs[$i][i]
    }
}
{
    PROCINFO["sorted_in"] = "@ind_num_asc"
    for (name in names2fldNrs) {
        c = 0
        for (fldNr in names2fldNrs[name]) {
            printf "%s%s", (c++ ? OFS : ""), $fldNr > name
        }
        print "" > name
    }
}

$ awk -f tst.awk file

$ cat A1BG
A1BG A1BG
aa bb
1 2

$ cat A1CF
A1CF A1CF
cc dd
3 4

$ cat A2ML1
A2ML1
ee

答案 4 :(得分:0)

由于您在其中一条评论中写道,您有20000列,我们可以考虑采用两步方法来简化调试,找出哪些步骤中断。

<强> step1.awk

  NR == 1 { PROCINFO["sorted_in"] = "@ind_num_asc"
            for( i=1; i<=NF; i++ ) { f2c[$i] = (f2c[$i]=="")? "$" i : (f2c[$i] " $" i) } }
  NR== 2 { for( fn in f2c) printf("%s:%s\n", fn,f2c[fn]) 
           exit
        }

Step1应该为我们提供一个文件列表以及他们的列:

> awk -f step1.awk yourfile
Mpap_1:$1, $2, $3, $5, $13, $19, $25
Mpap_2:$4, $6, $8, $12, $14, $16, $20, $22, $26, $28
Mpap_3:$7, $9, $10, $11, $15, $17, $18, $21, $23, $24, $27, $29, $30

在我的测试数据中,Mpap_1是第1,2,3,5,13,​​19,25栏中的标题。让我们希望这第一步适用于您的大量列。 (坦率地说:我不知道awk是否可以处理20000美元。)

第2步:让我们创建一个着名的一个衬垫:

> awk -f step1.awk yourfile | awk -F : 'BEGIN {print "{"}; {print "  print " $2, "> \""  $1 "\""  }; END { print "}" }' | awk -v "OFS=\t" -f - yourfile 

第一部分是我们的第1步,第二部分是动态构建第二个awk脚本,使用这样的行:print $1, $2, $3, $5, $13, $19, $25 > "Mpap_1"。第二个awk脚本通过管道传输到第三部分,该部分从stdin(-f -)读取脚本并将脚本应用于输入文件。

如果某些东西不起作用:观察step2的每个部分的输出,你可以执行左边的部分直到(但不包括)每个|符号,看看发生了什么,例如:

  • awk -f step1.awk yourfile
  • awk -f step1.awk yourfile | awk -F : 'BEGIN {print "{"}; {print " print " $2, "> \"" $1 "\"" }; END { print "}" }'

答案 5 :(得分:0)

以下为我工作:

step1.awk的代码:

NR == 1 {PROCINFO [“sorted_in”] =“@ ind_num_asc”             for(i = 1; i&lt; = NF; i ++){f2c [$ i] =(f2c [$ i] ==“”)? “$”我:(f2c [$ i]“\”\ t \“$”i)}}   NR == 2 {for(fn in f2c)printf(“%s:%s \ n”,fn,f2c [fn])            出口         }

然后运行一个使用上面awk脚本的衬垫:

awk -f step1.awk file.txt | awk -F:'BEGIN {print“{”}; {print“print”$ 2,“&gt; \”“$ 1”.txt“”\“”}; END {print“}”}'| awk -f - file.txt

这会输出制表符分隔的.txt文件,其中所有列都在一个文件中具有相同的标题。 (每种类型标题的单独文件)

感谢Lars Fischer和其他人。

干杯