如何使用awk在同一行中打印多个匹配项

如何使用awk在同一行中打印多个匹配项

您好,有一个表格文件(分隔符= \tA.txt

205 toto patho
207 tata benign
208 titi likely_patho

B.txt

210 lolo patho
211 lala benign
212 lili benign

我想要一个文件,如果第三列是“patho”或“likely_patho”,则打印第二列的值。通过这个例子,我们有:

A toto;titi
B lolo

为了做到这一点,我做了:

for bla in *.txt; do
r="$(basename -s ".txt" $bla)"
awk -v filename=$r '($3=="patho" || $3=="likely_patho") {print filename"\t"$2}' $bla >> result.txt ;
done

但是,如果文件包含多个匹配项(例如A.txt),则此代码为每个匹配项提供一行:

A toto
A titi
B lolo

我怎样才能有正确的输出?谢谢

答案1

使用任何 awk:

$ cat tst.awk
BEGIN {
    split(t,tmp)
    for ( i in tmp ) {
        tgts[tmp[i]]
    }
    FS = OFS = "\t"
}
FNR == 1 {
    fname = FILENAME
    sub(/\.[^.]*$/,"",fname)
}
$3 in tgts {
    hits[fname] = (fname in hits ? hits[fname] ";" : "") $2
}
END {
    for ( fname in hits ) {
        print fname, hits[fname]
    }
}

$ awk -v t='patho likely_patho' -f tst.awk *.txt
A       toto;titi
B       lolo

答案2

尝试 :

awk '  FNR==1 {  f=FILENAME;
                 sub(/\.[^.]*$/,"",f);
                 printf "%s%s\t",aline,f;
                 aline="\n";
                 s=""
       }
       ($3=="patho" || $3=="likely_patho"){
                 printf "%s%s",s,$2;
                 s="; "
       }
       END{print ""}
    ' ./*.txt

答案3

尝试一下(可以是一行)

awk -v filename="$r" 'BEGIN { string=filename "\t" }
          ($3=="patho" || $3=="likely_patho") {printf string $2; string=";" }
          END { printf "\n" } ' $bla >> result.txt ;

我使用string作为前缀,它将首先打印文件名,然后是分号。

您需要添加最后的换行符。

答案4

使用 perl(带有额外的换行符以提高可读性):

$ perl -MFile::Basename -F'\t' -le '
$f = fileparse($ARGV, qw(.txt)) if $. == 1;
if ($F[2] =~ /^(likely_)?patho$/) {
  push @{ $files{$f} }, $F[1]
};
close(ARGV) if eof;   # close each input file and reset the line counter $. at eof

END {
  foreach (sort keys %files) {
    print "$_\t", join(";",@{ $files{$_} })
  }
}' A.txt B.txt
A       toto;titi
B       lolo
  • -MFile::Basename告诉 perl 加载文件::基本名称模块。这是一个核心 Perl 模块,包含在 Perl 中。

  • -F设置字段分隔符(制表符),还启用 Perl 的-a自动拆分模式(将每个输入行拆分为名为 的数组@F,类似于 awk),以及 Perl 的-n迭代其输入的选项(行为类似于sed -nawk)。

  • -l启用自动处理行结束符(\n默认情况下)。简而言之,它从每个输入行的末尾删除换行符(使用 perl 的chomp()函数)并将它们添加到每个语句的末尾print

  • 所有 perl 命令行选项都记录在man perlrun.

该脚本迭代每个输入行,每当它在第三个字段($F[2]-perl 数组索引从零开始)中找到匹配项时,它就会将第二个字段添加到名为 的数组哈希 (HoA) 中%files。这是一个哈希(关联数组),其中键是基本文件名,值是第二字段字符串的数组。有关 perl 数据结构的更多信息,请参阅perldataperllol和的手册页。perldsc

当所有输入被读取和处理后,它以请求的格式输出数据,并按文件名排序。


注意:... if $. == 1;与该close(ARGV) if eof行一起确保仅在每个新文件的第一行提取基本文件名。这不是必需的,只是一个小的优化,只有当您有非常大的输入文件时才会有用。如果您喜欢稍微短一点的一行或者如果性能不是问题,请删除该close(ARGV) ...行和if $. == 1条件。

相关内容