2つのパラメータをawkと一致させて2つのファイルをマージする方法

2つのパラメータをawkと一致させて2つのファイルをマージする方法

ファイルがありますA.txt(9月= \t)。

Cycle   Well    Value   Target
1   A1  5.07368111264623    EC
1   A1  3.06982862746599    FT
1   A1  2.46545646544623    EC

2番目のファイルB.txt(sep = \t最初の列は空です。):

    Well    Fluor   Target  Content Sample
    A1  Cy5 EC  Unkn-01 2060563935
    A1  Cy5 FT  Unkn-09 2156515156

Content次の場合に追加したいB.txt列を追加したいと思います。A.txt両方 WellTarget両方のファイルのデータが同じで、結果を(C.txtsep = \t)として出力します。

Cycle   Well    Value   Target  Content
1   A1  5.07368111264623    EC  Unkn-01
1   A1  3.06982862746599    FT  Unkn-09
1   A1  2.46545646544623    EC  Unkn-01

私は次のことを試してみます:

awk -F"\t" 'FNR==NR{if (a[$2]) {a[$2]=a[$2] "\t" $7} else {a[$2]=$7}} NR>FNR{split($0,f,"\t"); if (a[f[4]]) $0=$0 "\t" a[f[4]]; print}'

しかし、それはうまくいきませんでした。これを行う方法を知っていますか?

正確:

  • テンプレートとして使用される最初のファイル(A.txt)には、同じ細孔とターゲットを持つ複数のリグニンがあります。
  • B.txtには、同じ穴/ターゲットの組み合わせを持つ行が1つだけあります。
  • ファイルAとファイルBが一致するパターンを持たないことは不可能です。

答え1

最初の解決策は以下を使用します。GNU awkまたはPOSIX awk

編集する:〜のようにエドモートンawkGNUのみのサポートに対する元の答えが間違っていると彼の意見に書きました。 (GNU文書とPOSIX文書の表現は少し混乱しています。)

GNUドキュメントawkのタイトル多次元配列POSIX準拠をサポートしていますawk。バラよりhttps://pubs.opengroup.org/onlinepubs/000095399/utilities/awk.html「多次元」またはを検索してくださいSUBSEP。これらの配列は実際には1次元です。

GNUawkもサポート配列の配列これは真の多次元配列です。

このコマンドバージョンにはGNUが必要ですawk

awk -F"\t" 'NR == FNR { a[$2][$4] = $5; next } { print $0, a[$2][$4] }' B.txt A.txt > C.txt

POSIX互換バリアント(*)はすべてと互換性awkがなければなりません。

awk -F"\t" 'NR == FNR { a[$2,$4] = $5; next } { print $0, a[$2,$4] }' B.txt A.txt > C.txt

両方印刷

Cycle   Well    Value   Target 
1   A1  5.07368111264623    EC Unkn-01
1   A1  3.06982862746599    FT Unkn-09
1   A1  2.46545646544623    EC Unkn-01

質問によると、Well / Targetキーはファイル内で一意であるため、ファイル内のデータは配列B.txtに保存されます。aその後、このデータはファイルのデータに追加されますA.txt

フィールド区切り文字を明示的に指定する必要があります。それ以外の場合は、awk空の列/値は無視されます。

このソリューションは、固定列番号を使用して一致または印刷する列を識別します。

編集する:\t索引式と区切り文字を明示的に組み合わせる次の解決策は、上記のPOSIX準拠の解決策(*)と比較して利点を提供しません。

awk -F"\t" 'NR == FNR { a[$2 "\t" $4] = $5; next } { print $0, a[$2 "\t" $4] }' B.txt A.txt > C.txt

これは構文を設定しSUBSEP = "\t"て使用するのと同じですa[$2, $4]


2番目の解決策は以下を使用します。キュー

ツールqは、CSVファイルに対してデータベースと同様のクエリを実行するために使用できます。

バラよりhttp://harelba.github.io/q/またはhttps://github.com/harelba/q

このソリューションには次の問題があります。の列ヘッダーが空ですB.txt。回避策として、Emptyファイルのヘッダー行にヘッダーを追加しました。

だから私は次のファイルを使用します。

A.txt

Cycle   Well    Value   Target
1   A1  5.07368111264623    EC
1   A1  3.06982862746599    FT
1   A1  2.46545646544623    EC

B.txt

Empty   Well    Fluor   Target  Content Sample
    A1  Cy5 EC  Unkn-01 2060563935
    A1  Cy5 FT  Unkn-09 2156515156

注文する

q -H -t "select a.Cycle,a.Well,a.Value,a.Target,b.Content from A.txt as a inner join B.txt as b on a.Well=b.Well and a.Target=b.Target"

印刷

1   A1  5.07368111264623    EC  Unkn-01
1   A1  3.06982862746599    FT  Unkn-09
1   A1  2.46545646544623    EC  Unkn-01

タイトルを印刷するには、printfまたはechoコマンドを追加できます。

printf "Cycle\tWell\tValue\tTarget\tContent\n" > C.txt
q -H -t "select a.Cycle,a.Well,a.Value,a.Target,b.Content from A.txt as a inner join B.txt as b on a.Well=b.Well and a.Target=b.Target" >> C.txt

B.txt利用可能なファイルを自動的に変更するには

printf "Empty" > B1.txt
cat B.txt >> B1.txt
printf "Cycle\tWell\tValue\tTarget\tContent\n" > C.txt
q -H -t "select a.Cycle,a.Well,a.Value,a.Target,b.Content from A.txt as a inner join B1.txt as b on a.Well=b.Well and a.Target=b.Target" >> C.txt

ソリューションは、ヘッダー行の名前付き列を使用して、一致または印刷する列を識別します。

答え2

2D配列用のGNUがあると仮定すると、awk次のプログラムはこれを行います。

awk -F'\t' 'NR==FNR&&FNR>1{map[$2][$4]=$5}\
            NR>FNR{if (FNR==1) {$5="Content"} else {$5=map[$2][$4]}} NR>FNR' B.txt A.txt > C.txt

まず、B.txt特定の「ウェル」と「ターゲット」の組み合わせに対する「コンテンツ」値のマッピング生成を処理します。後で処理するときA.txt( で示されるFNR、ファイルごとのラインカウンタが現在のグローバルNRラインカウンタよりも小さい)、プログラムは現在のラインで「Well」と「Target」の特定の組み合わせを探し、その「」を置き換えます。以前に作成されたマップコンテンツの値。2番目のファイルを処理した後にのみ出力を印刷します(「stray」のNR>FNR場合)。

関連情報