Shell-Script

即使 IDS 不匹配且列數不定,也可以根據 ID 合併 CSV 文件

  • October 18, 2019

我正在編寫一個 bash 腳本,該過程的一部分需要將 csv 文件拼湊在一起,同時保持列的完整性;例如,我有以下格式的兩個文件:

F1

ID,MD,L1,L2,L3,GD,L4
12,OB,AA,PP,AA,TT,AA
15,OB,PP,PP,PP,TT,AA

F2

ID,MD,L7,L8,L9,L10,GD
13,OB,PP,AA,AA,AA,AA
15,OB,PP,PP,PP,AA,AA

輸出將如下所示,其中不匹配的 ID 返回值 NM,重複列(在本例中為“GD”)根據每個文件的值顯示:

ID,MD,L1,L2,L3,GD,L4,L7,L8,L9,L10,GD
12,OB,AA,PP,AA,TT,AA,NM,NM,NM,NM,NM
13,NM,NM,NM,NM,NM,NM,PP,AA,AA,AA,AA
15,OB,PP,PP,PP,TT,AA,PP,PP,PP,AA,AA

我一直在努力join工作,因為它看起來很有希望,即 join -t, -eNM -a1 -a2 -o 0,1.2,1.3,1.4,1.5,1.6,1.7,1.8,2.3,... F1 F2

但我遇到了一些問題。

  1. 如果我使用該-o選項,它假定我知道每個文件的確切列數,而不是獨立變化。
  2. 錯誤洩漏到結果中: join: REPORT_2|15-10-2019|15:39:25.csv:5: is not sorted: 04181646

如果有其他選擇而不是join我願意接受建議。謝謝。

您可以使用 shell 腳本-o為您創建必要的選項並對輸入文件的數據進行排序。

這假設第二個欄位MD存在於兩個輸入文件中,並且只在輸出中列印一次(在第二個文件的選項中跳過)。

#!/bin/bash

opts="0,"

# file1: get number of columms - 1 from the first line
numcols=$(awk -F',' '(NR==1) {print NF-1}' "$1")

# file1: add options
for i in $(seq "$numcols"); do
 opts+=$(printf '1.%s,' "$((i+1))")
done

# file2: get number of columms - 2 from the first line
numcols=$(awk -F',' '(NR==1) {print NF-2}' "$2")

# file2: add options
for i in $(seq "$numcols"); do
 opts+=$(printf '2.%s,' "$((i+2))")
done

opts=${opts:0:-1} # remove the last `,`

join -t, --header -eNM -a1 -a2 -o "$opts"\
 <(head -n1 "$1"; tail -n+2 "$1" | sort -nk1,1)\
 <(head -n1 "$2"; tail -n+2 "$2" | sort -nk1,1)

我添加--header了將第一行視為標題行的選項。<(head -n1 "$1"; tail -n+2 "$1" | sort -nk1,1)用於列印標題行並按第一個欄位對剩餘行進行數字排序。

使腳本可執行

chmod +x join.sh

並將其執行為

./join.sh file1 file2

引用自:https://unix.stackexchange.com/questions/546910