問題
で、 join コマンドを用いて完全外部結合を行う方法が示されている。ただ、output のフォーマットを毎回指定するのはめんどい。かといってフォーマットがないと、下みたいに列がそろわず、あまりよくない感じで join されてしまう。具体的には、外部結合部分の、行の列の数が、異なって出力されてしまう。
problem-example
: 1.csv
hoge,100
fuga,200
piyo,300
: 2.csv
hoge,Adam
fuga,Bill
moge,Charlie
$ join -a 1 -a 2 -t, -j 1 1.csv 2.csv
hoge,100,Adam
fuga,200,Bill
moge,Charlie
piyo,300
解決方法
output のフォーマットを生成しながら join を実行することにより、この問題を解決する。
nice-join.sh
#!/bin/bash
if [ $# -ne 2 ]
then
echo "usage: $0 [-j num_field ][ -1 num_field1 ] [ -2 num_field2 ] 1.csv 2.csv" 1>&2
exit 1
fi
j1_field=1
j2_field=1
while true; do
case "$1" in
-j)
j1_field="$2"
j2_field="$2"
shift 2
;;
-1)
j1_field="$2"
shift 2
;;
-2)
j2_field="$2"
shift 2
;;
*)
break
;;
esac
done
count_commas() {
sed 's/[^,]//g' | wc -c
}
make_format() {
if [ $# -ne 3 ]
then
echo "usage: $0 file_num join_field num_commas" 1>&2
exit 1
fi
seq 1 $3 |
grep -v $2 |
awk -v num=$1 '{printf ("%s.%s\n",num,$0)}' |
{ tr '\n' , ; echo; } |
sed 's/,$//'
}
cat "$1" | {
exec 3<&0
read -r line1
num_commas1=$(printf '%s\n' "$line1" | count_commas)
format1=$(make_format 1 $j1_field $num_commas1)
cat "$2" | {
read -r line2
num_commas2=$(printf '%s\n' "$line2" | count_commas)
format2=$(make_format 2 $j2_field $num_commas2)
join -o 0,$format1,$format2 \
-a 1 -a 2 -t, \
-1 $j1_field -2 $j2_field <(
printf '%s\n' "$line1"
cat <&3
) <(
printf '%s\n' "$line2"
cat
)
}
exec 3<&-
}
how-to-use
$ nice-join.sh 1.csv 2.csv
hoge,100,Adam
fuga,200,Bill
moge,,Charlie
piyo,300,