awk を使用して異なるファイルから複数の列を結合する

awk を使用して異なるファイルから複数の列を結合する

次のような 4 つの tsv (タブ区切り) ファイルがあります。

ファイル_1:

abc 1
def 2
ghi 3

ファイル_2:

abc 2
ghi 3

ファイル_3:

def 1
ghi 2
jkl 4

ファイル_4:

ghi 3
jkl 4

これらのファイルを結合して、次のように 1 つの tsv ファイルを取得します。

dataset file_1 file_2 file_3 file_4
abc     1      2             
def     2      4            
ghi     3      3      2      3
jkl                   4      4

使ってみましたawk

$ awk '
    BEGIN{OFS=FS="\t"} 
    FNR==1{f = f "\t" FILENAME} 
    NR==FNR{a[$1] = $2} 
    NR!=FNR{a[$1] = a[$1] "\t" $2} 
    END{printf "dataset%s\n", f; for(i in a) print i, a[i]}
  ' file_{1..4}

このコマンドは機能しますが、シフトした値を取得しました。たとえば、1 列目と 2 列目の値が空で、3 列目と 4 列目の値が 4 と 4 の場合、そのコマンドから取得した出力は、1 列目と 2 列目の値が 4 ですが、3 列目と 4 列目の値が空です。そこで、awk前述の方法を使用して tsv ファイルを個別に結合してみます。最初に と のみを使用file_1file_2て を取得しoutput_1、次にfile_3と を結合してfile_4を取得しますoutput_2。その後、$ join output_1 output_2output_1 と output_2 をマージするために使用しますが、4 つのファイルに存在する値しか取得しません。1 つのファイルにのみ存在するデータを失いました。

アドバイスを頂ければ大変助かります。

ありがとう

答え1

$ cat tst.awk
BEGIN { FS=OFS="\t" }
{ datasets[$1]; fnames[FILENAME]; vals[$1,FILENAME] = $2 }
END {
    printf "%s", "dataset"
    for (fname in fnames) {
        printf "%s%s", OFS, fname
    }
    print ""
    for (dataset in datasets) {
        printf "%s", dataset
        for (fname in fnames) {
            printf "%s%s", OFS, vals[dataset,fname]
        }
        print ""
    }
}

$ tail -n +1 file?
==> file1 <==
a       1
b       2
c       3

==> file2 <==
a       2
c       3

$ awk -f tst.awk file1 file2
dataset file1   file2
a       1       2
b       2
c       3       3

好きなだけリストにファイルを追加できます。

答え2

join (GNU coreutils) 8.30「プロセス置換」を使用すると、

join -a1 -a2 -t"    " -oauto  -e " " <(join -a1 -a2 -t" " -oauto  -e "" file[12]) <(join -a1 -a2 -t"    " -oauto  -e " " file[34])
abc 1   2        
def 2       1    
ghi 3   3   2   3
jkl         4   4

オプションには文字値-tがあります<TAB>

答え3

現時点でのアドバイス: 後で必要になった場合に備えてコードを作成してください。

すべてのファイルを読み取るときに 3 つの配列を保持します。

(a) 新しいファイルごとに、ファイル名のハッシュリスト。
(b) 新しいデータセットごとに、$1 のハッシュリスト。
(c) 行ごとに、値のハッシュリスト

FNR == 1 { ++htFile[FILENAME]; }
! ($1 in htSet) { ++htSet[$1]; }
{ htVal [FILENAME, $1] = $2; }

End 関数で、htFile と htSet を反復処理します。

function Table (r, c, buf) {
    buf = "dataset";
    for (c in htFile)
        buf = sprint ("%s\t%s", buf, htFile[c]);
    print buf;
    for (r in htSet) {
        buf = "";
        for (c in htFile)
            buf = sprint ("%s\t%s", buf, htVal[c, r]);
        print substr (buf, 2);
    }
}
END { Table( ); }

出力テーブル内のファイルとデータセットの順序は維持されません。 順序が重要な場合は、テーブルの順序付けされたバージョンを保持し、元の順序で反復処理することができます。

関連情報