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



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

samples.txt

aa
bb
cc

input.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  

output.txt

aa    bb    cc
1     3     8
5     7     8

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

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

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

并遍历文件中的每一行,作为正则表达式使用,如上所述:

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

In 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 "%st",$i;print x}' {samples,input}.txt
aa      bb      cc
1       3       8
5       7       8

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

Then遍历每行,只打印数组中设置为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

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

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

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

在本例中,我们将samples中的所有名称加载到数组a[]中。然后,我们遍历input数据并检查它的第一个字段是否在数组中。如果是,则该语句的计算结果为True,并打印该行。

transpose是我在另一个答案中使用的函数:

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)
              }
        }'
}

如果你想要一个正则表达式比较,那么它是:

$ 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。

最新更新