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

3番目の列が「patho」または「likely_patho」の場合、2番目の列の値を印刷するファイルが必要です。この例では、次のようになります。

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)が含まれている場合、このコードは各一致に対して1行を提供します。

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

試してみてください(1行だけです)。

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::BasenamePerlにロードするように指示するファイル::デフォルト名基準寸法。これはPerlに含まれるコアPerlモジュールです。

  • -Fフィールド区切り文字(タブ)を設定し、Perlの-a自動分割モード(各入力行をawkと同様に名前付き配列に分割@F)と、-n入力を繰り返すPerlのオプション(sed -nと同様に動作awk)も有効にします。

  • -l行末自動処理を有効にします(\nデフォルト)。つまり、各入力行の末尾から改行文字を削除し(Perlのchomp()関数を使用して)、それを各ステートメントの最後に追加しますprint

  • すべてのPerlコマンドラインオプションはで説明されていますman perlrun

スクリプトは各入力行を繰り返し、3番目のフィールドで一致するものが見つかるたびに($F[2]-perl配列インデックスは0から始まります)、2番目のフィールドを(HoA)middleという配列ハッシュに追加します%files。これは、キーがデフォルトのファイル名で値が2番目のフィールドの文字列配列であるハッシュ(連想配列)です。 Perlデータ構造の詳細についてはperldataperllolおよびのマニュアルページを参照してください。perldsc

すべての入力を読み取り、処理したら、要求された形式でファイル名でソートされたデータを出力します。


注:... if $. == 1;このclose(ARGV) if eof行とともに、各新しいファイルの最初の行からデフォルトのファイル名のみが抽出されていることを確認してください。これは必須ではなく、非常に大きな入力ファイルがある場合にのみ役立つ小さな最適化です。少し短い行を好む場合やパフォーマンスが問題にならない場合は、行とclose(ARGV) ...条件if $. == 1を削除してください。

関連情報