bash:从文件中读取每一行并用作正则表达式来匹配和打印列awk

时间:2015-06-09 13:25:45

标签: regex bash awk

我想将文件的每一行samples.txt用作正则表达式,并打印与input.txt匹配的整个列。

SAMPLES.TXT

s   aa    v    dd    jj    bb    ww    cc
1   1     1    1     2     3     3     8
3   5     4    5     2     7     5     8  

input.txt中

aa    bb    cc
1     3     8
5     7     8

output.txt的

awk 'NR==1 {for(i=1;i<=NF;i++) if ($i~/$line/) f=i;next} {print $f}' input.txt

我可以单独执行这些操作 - 在bash中读取每一行然后将其用作正则表达式,并使用正则表达式单独打印匹配列,但我不能将它们放在一起。有什么建议吗?

要打印我可以使用的每个匹配列:

while read line; do echo $line; done < samples.txt

并遍历每行的文件以用作上面的正则表达式:

while read line; do
    awk 'NR==1 {for(i=1;i<=NF;i++) if ($i~/$line/) f=i;next} {print $f}' input.txt >> output.txt; done < samples.txt

但是我不能把这两个放在一起......

{{1}}

3 个答案:

答案 0 :(得分:3)

我认为转置input.txt文件更容易,打印那些以给定单词开头的行然后转置回来:

$ awk 'FNR==NR {a[$1]; next} $1 in a' samples <(transpose < input) | transpose
aa bb cc
1 3 8
5 7 8

在阅读awk 'FNR==NR {do_things; next} other_things' file1 file2时使用do_things执行file1,在阅读other_things时使用file2

在这种情况下,我们将samples中的所有名称加载到数组a[]中。然后,我们浏览input数据并检查其第一个字段是否在数组中。如果是,则语句​​的计算结果为True,并打印该行。

transpose是我在another answer中使用的函数:

transpose () {
  awk '{for (i=1; i<=NF; i++) a[i,NR]=$i; max=(max<NF?NF:max)}
        END {for (i=1; i<=max; i++)
              {for (j=1; j<=NR; j++) 
                  printf "%s%s", a[i,j], (j<NR?OFS:ORS)
              }
        }'
}

答案 1 :(得分:3)

在awk中

awk 'NR==FNR{a[$1]++;next}FNR==1{for(i=1;i<=NF;i++)b[i]=a[$i]}
            {for(i=1;i<=NF;i++)if(b[i])printf "%s\t",$i;print x}' {samples,input}.txt

aa      bb      cc
1       3       8
5       7       8

这基本上在第一个文件中收集数组中的样本。接下来在第二行的第一行,将每个字段与样本进行比较,如果它们相同则将它们设置为1.

然后遍历每一行只打印数组中设置为1的字段。

删除以下(Kent | Fedorqui | Ed Morton)建议的尾随标签

awk 'NR==FNR{a[$1]++;next}FNR==1{for(i=1;i<=NF;i++)b[i]=a[$i]==1&&last=i}
     {for(i=1;i<=NF;i++)if(b[i])printf "%s",$i (i==last?ORS:OFS)}' {samples,input}.txt

答案 2 :(得分:1)

如果您确实需要正则表达式比较,那么它是:

$ cat tst.awk
NR==FNR { colNames=(NR>1 ? colNames "|" : "") $0; next }
FNR==1 {
    numCols = 0
    for (i=1; i<=NF; i++) {
        if ( $i ~ "("colNames")" ) {
            colNrs[++numCols] = i
        }
    }
}
{
    for (i=1; i<=numCols; i++) {
        printf "%s%s", $(colNrs[i]), (i<numCols?OFS:ORS)
    }
}

$ awk -f tst.awk samples.txt input.txt
aa bb cc
1 3 8
5 7 8

如果你真的想要一个字符串比较,那么:

$ cat tst2.awk
NR==FNR { colNames[$0]; next }
FNR==1 {
    numCols = 0
    for (i=1; i<=NF; i++) {
        if ( $i in colNames ) {
            colNrs[++numCols] = i
        }
    }
}
{
    for (i=1; i<=numCols; i++) {
        printf "%s%s", $(colNrs[i]), (i<numCols?OFS:ORS)
    }
}

$ awk -f tst2.awk samples.txt input.txt
aa bb cc
1 3 8
5 7 8

要在多个输入文件上运行它,只需在awk命令行的末尾列出它们,不要编写shell循环来多次调用awk。