これが解決策です。エレガントなのかひどいのかわかりません。join
コマンド (したがってコマンドも) を悪用しsort
、さらにawk
.
file1=xx1
file2=xx2
join -t ' ' -j 1 -a 1 -a 2 -o 1.1,2.1,1.2,2.2 \
<(sort -b $file1 | awk '{printf("%s\t%s\t%s\t%s\t%s %s\n",$1,$2,$3,$4,$5,$6)}') \
<(sort -b $file2 | awk '{printf("%s\t%s\t%s\t%s\t%s %s\n",$1,$2,$3,$4,$5,$6)}') |
awk '{
if (NF == 6) sum = $6;
else sum = $11 + $12;
print $1, $2, $3, $4, $5, sum;
}'
ファイル名はパラメーターです。の<(sort -b $fileN | awk '...')
特徴である「プロセス置換」ですbash
。これは「括弧内のコマンドを実行する」ことを意味し、パイプラインの標準出力は名前付きファイル (通常は/dev/fd/NN
) としてコマンドに提供されます。この場合はjoin
. パイプラインはよこしまです。データを並べ替えてawk
から、キー フィールド (最初の 5 つのフィールド) がタブで区切られ、6 番目のフィールドが空白で区切られるようにデータをフォーマットします。はフィールドのsort -b
先頭の空白を無視します。それは正気の結果を得るために重要です。
このjoin
コマンドは空白をフィールド セパレータ ( ) として扱う-t ' '
ため、入力ファイルにはそれぞれ 2 つのフィールドがありますjoin
。結合は、最初のフィールドが等しい場合に発生します-j 1
(最初のフィールドはタブで区切られた 5 つの値のセットであることを思い出してください)。-a 1
出力には、ファイル 1 ( ) とファイル 2 ( )からの一致しないエントリが含まれます-a 2
。出力形式は、ファイル 1 からフィールド 1、ファイル 2 からフィールド 1、ファイル 1 からフィールド 2、ファイル 2 からフィールド 2 です。
一致する場合、出力には、空白またはタブで区切られた多数の列が含まれます。一致するものがない場合、出力には空白またはタブで区切られた半ダースの列が含まれます。
の後処理でawk
は、空白とタブがどちらもフィールドの区切り文字であるという事実を利用していますawk
。入力行に 6 つのフィールドがある場合、そのキーに一致するものがなかったため、合計が の値になり$6
ます。入力行にその他の数のフィールドがある場合 (12 にする必要があります)、合計は最後の 2 つのフィールドの値になります$11 + $12
。次に、スクリプトは最初の 5 つのフィールドと合計を出力します。
フィールド区切りとして空白とタブを使用するこのトリックは、おそらくグロテスクですが、このコンテキストではかなり効果的です。
サンプル データでは、特定のキー (最初の 5 列は各ファイルで一意) を持つ各ファイルに最大 1 行あるため、join
ファイル 1 の N 行とファイル 2 の M 行をペアにして NxM 出力を与えるという事実必要に応じて N = 1 および M = 1 であるため、行は重要ではありません。
出力例
質問に示されているデータ ファイル (およびファイル内のスクリプトjb.sh
)を考えると、次のようになります。
$ bash jb.sh
118 2 AA 4.25 30.25 7
119 2 AA 4.50 30.25 9
120 2 AA 4.75 30.25 3
120 2 AA 5.00 30.25 8
121 2 AA 5.00 30.25 13
122 2 AA 5.25 30.25 5
123 2 AA 5.50 30.25 6
124 2 AA 5.75 30.25 7
125 2 AA 6.00 30.25 8
126 2 AA 6.25 30.25 9
179 1 BB 19.75 30.00 1
180 1 BB 19.75 30.00 2
230 1 BB 32.25 30.00 3
231 1 BB 32.50 30.00 4
232 1 BB 32.75 30.00 5
$
この出力は目的の出力と同一ではないことに注意してください。これは、目的の出力が指定された入力に対して誤っているためです (または、目的の出力に対して入力が誤っているためです)。サンプル データには次の行があります。
120 2 AA 4.75 30.25 3
120 2 AA 5.00 30.25 8
列 4 はここでは同じではない (4.75 対 5.00) ため、これらの行を結合することはできず、'120' に対して 2 つの出力行が得られることに注意してください。
16列に拡張
スクリプトは少し整理されていますが、それ以外は以前と同じパターンが続きます。
file1=xx1
file2=xx2
sort_print()
{
sort -b "$@" |
awk '{printf("%s\t%s\t%s\t%s\t%s %s\t%s\t%s\t%s\t%s\t%s\t%s\t%s\t%s\t%s\t%s\n",
$1,$2,$3,$4,$5, $6,$7,$8,$9,$10,$11,$12,$13,$14,$15,$16)}'
}
join -t ' ' -j 1 -a 1 -a 2 -o 1.1,2.1,1.2,2.2 \
<(sort_print $file1) <(sort_print $file2) |
tee joined.data |
awk '{
if (NF != 16)
{
for (i = 6; i <= 16; i++)
{
j = i + 16
$i = $i + $j;
}
}
printf "%s %s %s %s %s", $1, $2, $3, $4, $5;
for (i = 6; i <= 16; i++)
printf " %s", $i;
printf "\n";
}'
ファイルxx1
118 2 AA 4.25 30.25 1 2 3 4 5 14 5 4 5 7 8
119 2 AA 4.50 30.25 2 2 3 4 5 4 15 4 5 7 8
120 2 AA 5.00 30.25 3 2 3 4 5 4 5 14 5 7 8
121 2 AA 5.00 30.25 4 2 3 4 5 4 5 4 15 7 8
122 2 AA 5.25 30.25 5 2 3 4 5 4 5 4 5 17 8
123 2 AA 5.50 30.25 6 2 13 4 5 4 5 4 5 7 18
124 2 AA 5.75 30.25 7 2 3 4 5 4 5 4 5 7 18
125 2 AA 6.00 30.25 8 12 3 4 5 4 5 4 5 7 18
126 2 AA 6.25 30.25 9 2 3 4 5 4 5 4 5 7 18
ファイルxx2
179 1 BB 19.75 30.00 1 8 21 2 4 12 2 3 1 9 1032
180 1 BB 19.75 30.00 2 29 1 22 4 12 2 3 1 9 1042
230 1 BB 32.25 30.00 3 9 8 2 44 12 2 3 1 9 1052
231 1 BB 32.50 30.00 4 9 17 2 44 12 2 3 1 9 1062
232 1 BB 32.75 30.00 5 9 8 1 4 122 2 3 1 9 1072
118 2 AA 4.25 30.25 6 9 8 1 2 4 22 3 1 9 1082
119 2 AA 4.50 30.25 7 29 8 1 2 4 12 23 1 9 1092
120 2 AA 5.00 30.25 8 9 8 1 2 4 12 2 21 9 1002
121 2 AA 5.00 30.25 9 9 8 1 2 4 12 2 3 29 1012
出力
118 2 AA 4.25 30.25 124 11 8 5.25 32.25 5 24 6 5 14 1096
119 2 AA 4.50 30.25 126 31 8 5.5 32.25 6 14 26 5 14 1096
120 2 AA 5.00 30.25 128 11 8 6 32.25 7 14 5 25 14 1006
121 2 AA 5.00 30.25 130 11 8 6 32.25 8 14 5 7 34 1016
122 2 AA 5.25 30.25 5 2 3 4 5 4 5 4 5 17 8
123 2 AA 5.50 30.25 6 2 13 4 5 4 5 4 5 7 18
124 2 AA 5.75 30.25 7 2 3 4 5 4 5 4 5 7 18
125 2 AA 6.00 30.25 8 12 3 4 5 4 5 4 5 7 18
126 2 AA 6.25 30.25 9 2 3 4 5 4 5 4 5 7 18
179 1 BB 19.75 30.00 1 8 21 2 4 12 2 3 1 9 1032
180 1 BB 19.75 30.00 2 29 1 22 4 12 2 3 1 9 1042
230 1 BB 32.25 30.00 3 9 8 2 44 12 2 3 1 9 1052
231 1 BB 32.50 30.00 4 9 17 2 44 12 2 3 1 9 1062
232 1 BB 32.75 30.00 5 9 8 1 4 122 2 3 1 9 1072