2つのファイルをawkで結合する


9

File1.txt

item1   carA
item2   carB
item3   carC
item4   platD
item5   carE

File2.txt

carA  platA
carB  platB
carC  platC
carE  platE

必要な出力:

item1   platA
item2   platB
item3   platC
item4   platD
item5   platE

どうすればできますか?

回答:


11

以下の回答は、いくつかの関連する変更を加えたSOの同様のQ&Aに基づいています。

$ awk 'FNR==NR {dict[$1]=$2; next} {$2=($2 in dict) ? dict[$2] : $2}1' file2.txt file1.txt 
item1 platA
item2 platB
item3 platC
item4 platD
item5 platE

アイデアは、インデックス付きのハッシュマップを作成し、辞書として使用することです。

コメントで質問した2番目の質問(2番目の列がfile1.txt6 番目の列になる場合の変更点):

入力ファイルが次のようになる場合file1b.txt

item1 A5 B C D carA
item2 A4 1 2 3 carB
item3 A3 2 3 4 carC
item4 A2 4 5 6 platD
item5 A1 7 8 9 carE

次のコマンドを実行します。

$ awk 'FNR==NR {dict[$1]=$2; next} {$2=($6 in dict) ? dict[$6] : $6;$3="";$4="";$5="";$6=""}1' file2.txt file1b.txt 
item1 platA    
item2 platB    
item3 platC    
item4 platD    
item5 platE    

1
@pawana-コメントの2番目の質問も解決するように回答を更新しました。私があなたの質問に答えたらそれを受け入れてください。
Yaron、2018年

6

私はあなたが言ったのを知っていますawk、しかしjoinこの目的のためのコマンドがあります...

{
  join -o 1.1,2.2 -1 2 -2 1 <(sort -k 2 File1.txt) <(sort -k 1 File2.txt)     
  join -v 1 -o 1.1,1.2 -1 2 -2 1 <(sort -k 2 File1.txt) <(sort -k 1 File2.txt) 
} | sort -k 1

次のjoin行がなければ、最初のコマンドで十分です。

item4   platD

コマンドは基本的に、最初のファイルの2列目(-1 2)と2番目のファイルの1列目(-2 1)に基づいて結合し、最初のファイルの1列目と2番目のファイルの2列目()を出力します-o 1.1,2.2。それはペアになったラインのみを表示します。2番目のjoinコマンドはほとんど同じことを言っていますが、ペアにできなかった最初のファイルの行を表示し(-v 1)、最初のファイルの最初の列と最初のファイルの2番目の列を出力します(-o 1.1,1.2)。次に、両方の出力を組み合わせて並べ替えます。sort -k 1最初の列にsort -k 2基づいて並べ替えることを意味し、2番目の列に基づいて並べ替えることを意味します。に渡す前に、結合列に基づいてファイルをソートすることが重要joinです。

今、私はそれを助けることができるならファイルで私のディレクトリを散らかしたくないので、私はソートを2回書いた。ただし、David Foersterが言ったように、ファイルのサイズによっては、ファイルを並べ替えて最初に保存し、それぞれを2回並べ替えるのを待たないようにすることができます。サイズのアイデアを与えるために、これは私のコンピューターで100万行と1000万行を並べ替えるのにかかる時間です:

$ ruby -e '(1..1000000).each {|i| puts "item#{i}   plat#{i}"}' | shuf > 1million.txt 
$ ruby -e '(1..10000000).each {|i| puts "item#{i}   plat#{i}"}' | shuf > 10million.txt 
$ head 10million.txt 
item530284   plat530284
item7946579   plat7946579
item1521735   plat1521735
item9762844   plat9762844
item2289811   plat2289811
item6878181   plat6878181
item7957075   plat7957075
item2527811   plat2527811
item5940907   plat5940907
item3289494   plat3289494
$ TIMEFORMAT=%E
$ time sort 1million.txt >/dev/null
1.547
$ time sort 10million.txt >/dev/null
19.187

100万行で1.5秒、1000万行で19秒です。


この場合、並べ替えが重要なサイズのデータ​​セットの場合、並べ替えに非常に時間がかかるため、並べ替えられた入力データを(一時的な)中間ファイルに保存する方が適切です。それ以外の場合は+1。
David Foerster

@Davidそれは良い点です。個人的に、私は中間ファイルを作成する必要が本当に嫌いですが、実行時間の長いプロセスにも焦っています。「簡単なサイズ」が何であるかと思ったので、小さなベンチマークを作成し、あなたの提案とともに回答に追加しました。
JoL、2018年

1つのmioレコードをソートすることは、かなり最近のデスクトップコンピュータでは十分高速です。さらに2桁3桁増加すると、さらに興味深いものが始まります。いずれの場合でも%E、(時間形式の)経過(実際の)時間は、計算パフォーマンスを測定するのにはあまり興味がありません。ユーザーモードのCPU時間(%Uまたは単に設定されていないTIMEFORMAT変数)の方がはるかに意味があります。
David Foerster

@David私はさまざまな時代のユースケースに精通していません。なぜもっと面白いのですか?経過時間は私が実際に待っている時間と一致するものです。1.5秒のコマンドの場合、で4.5秒になり%Uます。
JoL 2018年

1
経過時間は、同じシステムで実行されている他のタスクを待機し、I / O要求をブロックするのに費やされた時間の影響を受けます。(ユーザー)CPU時間はそうではありません。通常、計算上バインドされたアルゴリズムの速度を比較する場合、I / Oを無視して、他のバックグラウンドタスクによる測定エラーを回避したいとします。重要な質問は、「このアルゴリズムでは、そのデータセットでどれだけの計算が必要になるか」です。代わりに、「計算が完了するのを待っている間、コンピュータはすべてのタスクにどれだけの時間を費やしましたか?」
David Foerster
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.