2つのファイルAとBを取得し、次のような結果を出力するにはどうすればよいですか。
ファイルA:
001 Apple, CA
020 Banana, CN
023 Apple, LA
045 Orange, TT
101 Orange, OS
200 Kiwi, AA
ファイルB:
01-Dec-2013 01.664 001 AAA CAC 1083
01-Dec-2013 01.664 020 AAA CAC 0513
01-Dec-2013 01.668 023 AAA CAC 1091
01-Dec-2013 01.668 101 AAA CAC 0183
01-Dec-2013 01.674 200 AAA CAC 0918
01-Dec-2013 01.674 045 AAA CAC 0918
01-Dec-2013 01.664 001 AAA CAC 2573
01-Dec-2013 01.668 101 AAA CAC 1091
01-Dec-2013 01.668 020 AAA CAC 6571
01-Dec-2013 01.668 023 AAA CAC 2148
01-Dec-2013 01.674 200 AAA CAC 0918
01-Dec-2013 01.668 045 AAA CAC 5135
結果:
01-Dec-2013 01.664 001 AAA CAC 1083 Apple, CA
01-Dec-2013 01.664 020 AAA CAC 0513 Banana, CN
01-Dec-2013 01.668 023 AAA CAC 1091 Apple, LA
01-Dec-2013 01.668 101 AAA CAC 0183 Orange, OS
01-Dec-2013 01.674 200 AAA CAC 0918 Kiwi, AA
01-Dec-2013 01.674 045 AAA CAC 0918 Orange, TT
01-Dec-2013 01.664 001 AAA CAC 2573 Apple, CA
01-Dec-2013 01.668 101 AAA CAC 1091 Orange, OS
01-Dec-2013 01.668 020 AAA CAC 6571 Banana, CN
01-Dec-2013 01.668 023 AAA CAC 2148 Apple, LA
01-Dec-2013 01.674 200 AAA CAC 0918 Kiwi, AA
01-Dec-2013 01.668 045 AAA CAC 5135 Orange, TT
(ファイルA:番号はファイルBの中央の番号と一致する必要があります)
これを行うための可能な方法はありますか?
Awkを使用した簡単なソリューション:
awk -v FILE_A="file-A" -v OFS="\t" 'BEGIN { while ( ( getline < FILE_A ) > 0 ) { VAL = $0 ; sub( /^[^ ]+ /, "", VAL ) ; DICT[ $1 ] = VAL } } { print $0, DICT[ $3 ] }' file-B
コメント付きのバージョンは次のとおりです。
awk -v FILE_A="file-A" -v OFS="\t" '
BEGIN {
# Loop on the content of file-A
# to put the values in a table
while ( ( getline < FILE_A ) > 0 ){
# Remove the index from the value
VAL = $0
sub( /^[^ ]+ /, "", VAL )
# Fill the table
DICT[ $1 ] = VAL
}
}
{
# Print the line followed by the
# corresponding value
print $0, DICT[ $3 ]
}' file-B
これがあなたが探していることをするBashスクリプトです。スクリプトはmergeAB.bash
と呼ばれます。
#!/bin/bash
readarray A < fileA.txt
i=0
while read -r B; do
idx=$(( $i % ${#A[@]} ))
printf "%s %s" "$B" "${A[$idx]}"
#echo "i: $i | A#: ${#A[@]} | IDX: $idx"
let i=i+1
done < fileB.txt
あなたがそれを実行するとき:
$ ./mergeAB.bash
01-Dec-2013 01.664 001 AAA CAC 1083 001 Apple, CA
01-Dec-2013 01.664 020 AAA CAC 0513 020 Banana, CN
01-Dec-2013 01.668 023 AAA CAC 1091 023 Apple, LA
01-Dec-2013 01.668 101 AAA CAC 0183 045 Orange, TT
01-Dec-2013 01.674 200 AAA CAC 0918 101 Orange, OS
01-Dec-2013 01.674 045 AAA CAC 0918 200 Kiwi, AA
01-Dec-2013 01.664 001 AAA CAC 2573 001 Apple, CA
01-Dec-2013 01.668 101 AAA CAC 1091 020 Banana, CN
01-Dec-2013 01.668 020 AAA CAC 6571 023 Apple, LA
01-Dec-2013 01.668 023 AAA CAC 2148 045 Orange, TT
01-Dec-2013 01.674 200 AAA CAC 0918 101 Orange, OS
01-Dec-2013 01.668 045 AAA CAC 5135 200 Kiwi, AA
最初に行うことは、コマンドreadarray
を使用して、fileA.txt
の内容を配列に読み込むことです。これはBash4.xの新しい機能であるため、古いバージョンのBashを使用している場合は、代わりに次のようなものを使用できます。
$ IFS=$'\n' read -d '' -r -a A < fileA.txt
このスクリプトの残りの部分は少し複雑ですが、コメントを外して何が起こっているかを確認できるように、途中に冗長なecho
を残しました。
$ ./mergeAB.bash | grep i:
i: 0 | A#: 6 | IDX: 0
i: 1 | A#: 6 | IDX: 1
i: 2 | A#: 6 | IDX: 2
i: 3 | A#: 6 | IDX: 3
i: 4 | A#: 6 | IDX: 4
i: 5 | A#: 6 | IDX: 5
i: 6 | A#: 6 | IDX: 0
i: 7 | A#: 6 | IDX: 1
i: 8 | A#: 6 | IDX: 2
i: 9 | A#: 6 | IDX: 3
i: 10 | A#: 6 | IDX: 4
i: 11 | A#: 6 | IDX: 5
何が起きてる? $i
からの各行をループするときにカウントするために使用するカウンターfileB.txt
があります。次に、$idx
の現在の値と$i
の行数のモジュロ除算を計算することにより、fileA.txt
を計算します。
注:配列の長さA
。この方法で$idx
を計算することにより、0から5、次に0から5などに「ループ」させることができます。上記のデバッグ出力では、IDX:
列でこれを確認できます。
スクリプトの残りの部分はかなり標準的であり、printf
を使用して、fileB.txt
からの連結行とfileA.txt
からの対応する行を出力します。
join
ユーティリティは、指定されたファイルに対して「等式結合」を実行し、結果を標準出力に書き込みます。 「結合フィールド」は、ファイルが比較される各ファイルのフィールドです。
つまり、列を共有する2つのファイルがあります。列が等しいファイルの行を結合できます。
では、試してみましょう。
$ join -1 1 -2 3 a b
001 Apple, CA 01-Dec-2013 01.664 AAA CAC 1083
020 Banana, CN 01-Dec-2013 01.664 AAA CAC 0513
023 Apple, LA 01-Dec-2013 01.668 AAA CAC 1091
101 Orange, OS 01-Dec-2013 01.668 AAA CAC 0183
200 Kiwi, AA 01-Dec-2013 01.674 AAA CAC 0918
うん、動作します。ただし、指定した形式ではありません。それでは、ファイルを交換しましょう。
$ join -1 3 -2 1 b a
001 01-Dec-2013 01.664 AAA CAC 1083 Apple, CA
020 01-Dec-2013 01.664 AAA CAC 0513 Banana, CN
023 01-Dec-2013 01.668 AAA CAC 1091 Apple, LA
101 01-Dec-2013 01.668 AAA CAC 0183 Orange, OS
200 01-Dec-2013 01.674 AAA CAC 0918 Kiwi, AA
ずっといい。結合されたフィールドが最初に表示されるため、まだ完全には正しくありません。 Awkはそれを修正することができます:
$ join -1 3 -2 1 b a | awk '{print $2,$3,$1,$4,$5,$6,$7,$8}'
01-Dec-2013 01.664 001 AAA CAC 1083 Apple, CA
01-Dec-2013 01.664 020 AAA CAC 0513 Banana, CN
01-Dec-2013 01.668 023 AAA CAC 1091 Apple, LA
01-Dec-2013 01.668 101 AAA CAC 0183 Orange, OS
01-Dec-2013 01.674 200 AAA CAC 0918 Kiwi, AA
だからあなたは行きます。フィールドは同じ順序です。 awk
では、printf
を使用するか、正確な間隔を取得したい場合はいくつかのタブを挿入できますが、アイデアは得られると思います。
$ cat b |読みながらb; do key = $(echo $ b | awk '{print $ 3}');/bin/echo -n "$ b"; grep -w $ key a |カット-d\-f2-;完了 01-Dec-2013 01.664 001 AAA CAC 1083 Apple、CA 01-Dec-2013 01.664 020 AAA CAC 0513 Banana、CN 01-Dec-2013 01.668 023 AAA CAC 1091 Apple、LA 01-Dec-2013 01.668 101 AAA CAC 0183 Orange、OS 01-Dec-2013 01.674 200 AAA CAC 0918 Kiwi、AA 01-Dec- 2013 01.674 045 AAA CAC 0918 Orange、TT 01-Dec-2013 01.664 001 AAA CAC 2573 Apple、CA 01-Dec-2013 01.668 101 AAA CAC 1091 Orange、OS 2013年12月1日01.668020 AAA CAC 6571バナナ、CN 2013年12月1日01.668023 AAA CAC 2148アップル、LA 2013年12月1日01.674200 AAA CAC 0918キウイ、AA 01-Dec-2013 01.668 045 AAA CAC 5135 Orange、TT
awk
構文はもっとエレガントな方法で実行できると思いますが、うまくいくようです。
配列を使用して、要求に応じて(完全にbash
に)...
while read num loc; do A[0x$num]=$loc; done < A
while read B; do set -- $B; echo "${B} ${A[0x$3]}"; done < B
(bash v2で動作します)
最初の行は、ファイルAから配列 "A"をロードします。x $ numビットは、すべてを同じ基数に保つことです。そうでない場合、先行ゼロはそれらを8進数にします。 2行目は、ファイルBの各行を読み取り(スペースを保持)、その行から位置引数を設定し、最後にその行と「A」からのインデックス付きエントリを出力します。