使用 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}

這個指令是有效的,但我得到了轉移的值。假設,如果第一列和第二列的值為空,第三列和第四列的值為4 和4,則我從該命令獲得的輸出第一列和第二列的值為4,但第三列和第四列的輸出為空值。所以我嘗試使用awk我提到的單獨加入我的 tsv 檔案。先只為file_1file_2得到output_1,然後加入file_3file_4得到output_2。之後,我使用$ join output_1 output_2合併output_1和output_2,但我只獲得4個檔案中存在的值。我丟失了僅存在於一個文件中的資料。

如果您能給我建議,我將非常感激。

謝謝

答案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

現在的建議:如果您需要的話,可以稍後編寫程式碼。

當您讀取所有文件時,我會保留三個數組。

(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( ); }

這不會維護輸出表中檔案和資料集的順序。如果這很重要,您可以保留表的排序版本並按原始順序進行迭代。

相關內容