最初の 3 つのフィールドを awk で組み合わせるのがおそらく最も簡単です:
awk '{print $1 "_" $2 "_" $3 " " $4}' filename
次に、 join
を使用できます 通常は「フィールド 1」に
あなたはこれを試すことができます
awk '{
o1=$1;o2=$2;o3=$3
$1=$2=$3="";gsub(" +","")
_[o1 FS o2 FS o3]=_[o1 FS o2 FS o3] FS $0
}
END{ for(i in _) print i,_[i] }' file1 file2
出力
$ ./shell.sh
foo 1 scaf 3 4.5
bar 2 scaf 3.3 1.00
foo 1 boo 2.3
珍しい行を省略したい場合
awk 'FNR==NR{
s=""
for(i=4;i<=NF;i++){ s=s FS $i }
_[$1$2$3] = s
next
}
{
printf $1 FS $2 FS $3 FS
for(o=4;o<NF;o++){
printf $i" "
}
printf $NF FS _[$1$2$3]"\n"
} ' file2 file1
出力
$ ./shell.sh
foo 1 scaf 3 4.5
bar 2 scaf 3.3 1.00
これが正解です 回答 (標準の GNU coreutils の使用に関して) ツール、および perl/awk でカスタム スクリプトを記述しない 名前を付けてください)。
$ join -j1 -o1.2,1.3,1.4,1.5,2.5 <(<file1 awk '{print $1"-"$2"-"$3" "$0}' | sort -k1,1) <(<file2 awk '{print $1"-"$2"-"$3" "$0}' | sort -k1,1)
bar 2 scaf 3.3 1.00
foo 1 scaf 3 4.5
わかりました、どのように機能しますか:
<オール>
まず、優れたツール join
を使用します 2行をマージできます。 join
2 つの要件があります:
- 参加できます 1 つのフィールドのみ。
- 両方のファイルを並べ替える必要があります キー列別
キーを生成する必要があります 入力ファイルで、そのために単純な awk
を使用します スクリプト:
$ cat file1
foo 1 scaf 3
bar 2 scaf 3.3
$ <file1 awk '{print $1"-"$2"-"$3" "$0}'
foo-1-scaf foo 1 scaf 3
bar-2-scaf bar 2 scaf 3.3
ご覧のとおり、「foo-1-scaf」のようなキーを持つ最初の列を追加しました ".file2 でも同じことを行います .ところで。 <file awk
、 awk file
を書くための空想的な方法です 、または cat file | awk
.
並べ替えも必要です キーによるファイル。この場合、これは列 1 であるため、コマンドの最後に | sort -k1,1
を追加します。 (並べ替え 1 列目から 1 列目までのテキスト)
この時点で、ファイル file1.with.key を生成するだけです。 file2.with.key それらを結合しますが、それらのファイルが巨大であると仮定すると、それらをファイルシステムにコピーしたくありません。代わりに bash
と呼ばれるものを使用できます 名前付きパイプへの出力を生成する置換を処理します (これにより、不要な中間ファイルの作成が回避されます)。詳細については、提供されたリンクをお読みください。
ターゲットの構文は次のとおりです:join <( some command ) <(some other command)
最後に、複雑な結合引数について説明します:-j1 -o1.2,1.3,1.4,1.5,2.5
-j1
- 1 列目のキーで結合 (両方のファイル)-
-o
- これらのフィールドのみを出力1.2
(最初のファイル フィールド 2)、1.3
(最初のファイルの列 3) などこのように行を結合しましたが、
join
必要な列のみを出力します。
この投稿から得られる教訓は次のとおりです。
- coreutils を習得する必要があります これらのツールは組み合わせると非常に強力になり、ほとんど必要ありません。 そのような場合に対処するカスタム プログラムを作成する
- コア ユーティリティ ツールも非常に高速で、十分にテストされているため、常に最良の選択です。
結合コマンドは使いにくく、1 つの列でしか結合できません
広範な実験とマニュアル ページの綿密な精査により、複数の列を直接結合することはできないことが示されました。また、私の結合の実際の例はすべて、おかしなことに、結合する列を 1 つだけ使用しています。
したがって、どのような解決策でも、結合する列を何らかの形で 1 つの列に連結する必要があります。標準の結合コマンドでは、入力が正しい並べ替え順序になっている必要もあります。GNU の結合 (info coreutils join) には、並べ替えられたデータが必ずしも必要ではないという記述があります。
<ブロック引用>ただし、GNU 拡張機能として、入力にペアにできない行がない場合、ソート順は、上記のソート比較で 2 つのフィールドが等しいと見なされる場合にのみ、2 つのフィールドが等しいと見なされる任意の順序にすることができます。
与えられたファイルでそれを行う 1 つの可能な方法は次のとおりです:
awk '{printf("%s:%s:%s %s %s %s %s\n", $1, $2, $3, $1, $2, $3, $4);}' file1 |
sort > sort1
awk '{printf("%s:%s:%s %s %s %s %s\n", $1, $2, $3, $1, $2, $3, $4);}' file2 |
sort > sort2
join -1 1 -2 1 -o 1.2,1.3,1.4,1.5,2.5 sort1 sort2
これにより、最初に「:」を使用してサブフィールドを区切る複合ソート フィールドが作成され、2 つのファイルのそれぞれについてファイルがソートされます。 join コマンドは 2 つの複合フィールドを結合しますが、非複合 (非結合) フィールドのみを出力します。
出力は次のとおりです:
bar 2 scaf 3.3 1.00
foo 1 scaf 3 4.5
join ができないことをさせようとして失敗した
join -1 1 -2 1 -1 2 -2 2 -1 3 -2 3 -o 1.1,1.2,1.3,1.4,2.4 file1 file2
MacOS X 10.6.3 では、次のようになります:
$ cat file1
foo 1 scaf 3
bar 2 scaf 3.3
$ cat file2
foo 1 scaf 4.5
foo 1 boo 2.3
bar 2 scaf 1.00
$ join -1 1 -2 1 -1 2 -2 2 -1 3 -2 3 -o 1.1,1.2,1.3,1.4,2.4 file1 file2
foo 1 scaf 3 4.5
bar 2 scaf 3.3 4.5
$
これはフィールド 3 (のみ) に参加しています - これは望んでいるものではありません。
入力ファイルが正しいソート順になっていることを確認する必要があります。