linux grep模式在未知数量的列中

时间:2016-10-03 02:14:04

标签: linux bash awk sed grep

我有一个包含许多行和列的文本文件,我希望通过'列名称' grep一列。

    M121    M125    M123    M124    M131    M126    M211    N
0.41463252  1.00296561  -0.1713496  0.15923644  -1.49682602 -1.9478695  1.45223392  …
-0.46775802 0.14591103  1.122446    0.83648981  -0.3038532  -1.1841548  2.18074729  …
0.67736835  2.12969375  -0.8187298  0.13582824  -1.49290987 -0.6798428  1.04353114  …
0.08673344  -0.40437672 1.8441559   -0.63679375 0.47998832  0.1702844   0.54029264  …
-0.32606297 -0.95551833 0.6157599   0.02819133  1.44818627  -0.9528659  0.09207864  …
-0.51781121 0.88806507  -0.2913757  -0.00463802 0.05037374  0.953773    0.01244763  …
-0.25724472 0.05119051  0.2109025   -0.26083822 -0.52094072 -0.938595   -0.01275275 …
1.94348766  -1.83607523 1.2010512   -0.54109756 -0.88323831 -0.6263788  -0.96973544 …
0.1900408   -0.61025656 0.4586306   -0.69181051 -0.90713834 0.3589271   0.6870383   …
0.54866057  -0.03861159 -1.505861   0.54871682  -0.24602601 -0.3941754  0.85673905  …

例如,我想grep M211专栏,但我不知道专栏的数量。我试过了:

awk '$i == "M211"' filename or  awk '$0 == "M211"' filename

awk:非法字段$(),名称"我"  输入记录号1,文件名  源行号1

有什么解决方案吗?谢谢。

4 个答案:

答案 0 :(得分:3)

awk解决方案 - 迭代第一行输入文件的列名,并在符合所需模式时保存列号。然后打印该列。如果找不到匹配则没有输出

$ awk 'NR==1{ for(i=1;i<=NF;i++){if($i=="M125")c=i;} if(c==0)exit; }
       {print $c}' ip.txt
M125
1.00296561
0.14591103
2.12969375
-0.40437672
-0.95551833
0.88806507
0.05119051
-1.83607523
-0.61025656
-0.03861159


perl

类似的解决方案
$ perl -lane '@i = grep {$F[$_] eq "M123"} 0..$#F if $.==1; exit if !@i;
              print @F[@i]' ip.txt
M123
-0.1713496
1.122446
-0.8187298
1.8441559
0.6157599
-0.2913757
0.2109025
1.2010512
0.4586306
-1.505861
  • @i = grep {$F[$_] eq "M123"} 0..$#F if $.==1作为标题行,获取哪个列值与字符串M123匹配的索引
  • 如果找不到匹配项,则
  • exit if !@i退出
  • print @F[@i]打印匹配的列
  • 假设只有一个列匹配

对于多个匹配,请使用

perl -lane '@i = grep {$F[$_] =~ /^(M121|M126)$/} 0..$#F if $.==1; exit if !@i;
            print join " ", @F[@i]' ip.txt

答案 1 :(得分:2)

awk中的另一个人:

$ awk 'NR==1 {for(i=NF;i>0;i--) if($i=="M125") break; if(!i) exit} {print $i}' file
M125
1.00296561
0.14591103
2.12969375
-0.40437672
-0.95551833
0.88806507
0.05119051
-1.83607523
-0.61025656
-0.03861159

说明:

NR==1 {                       # for the first record
    for(i=NF;i>0;i--)         # iterate fields backwards for change
        if($i=="M125") break  # until desired column, remember i
    if (!i) exit              # if column not found, exit
} 
{print $i}                    # print value from ith field

答案 2 :(得分:1)

如果您对Python更熟悉:

import csv
column_name = "M125"
with open("file", "rb") as f:
  data_dict = csv.DictReader(f, delimiter=" ")
  print column_name
  for item in data_dict:
    print item[column_name]

答案 3 :(得分:1)

要按名称而不是数字对列(“awk中的”字段“)执行任何操作,您应首先创建一个将字段名称映射到数字的数组,然后使用由字段名称索引的数组访问字段( s)而不是通过字段编号直接访问它们:

$ awk 'NR==1{for (i=1;i<=NF;i++) f[$i]=i} {print $(f["M124"])}' file
M124
0.15923644
0.83648981
0.13582824
-0.63679375
0.02819133
-0.00463802
-0.26083822
-0.54109756
-0.69181051
0.54871682

或者如果您不想对列名进行硬编码:

$ awk -v c=M124 'NR==1{for (i=1;i<=NF;i++) f[$i]=i} {print $(f[c])}' file
M124
0.15923644
0.83648981
0.13582824
-0.63679375
0.02819133
-0.00463802
-0.26083822
-0.54109756
-0.69181051
0.54871682

并按您选择的顺序打印任意数量的列:

$ awk -v cols='M129 M124' 'NR==1{for (i=1;i<=NF;i++) f[$i]=i; n=split(cols,c)} {for (i=1;i<=n;i++) printf "%s%s", $(f[c[i]]), (i<n ? OFS : ORS)}' file
M129 M124
1.45223392 0.15923644
2.18074729 0.83648981
1.04353114 0.13582824
0.54029264 -0.63679375
0.09207864 0.02819133
0.01244763 -0.00463802
-0.01275275 -0.26083822
-0.96973544 -0.54109756
0.6870383 -0.69181051
0.85673905 0.54871682