web-dev-qa-db-ja.com

2つのファイルをawkと組み合わせる

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

どうすればいいですか?

9
pawana

以下の回答は、 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番目の質問について(file1.txtの2番目の列が6番目の列になる場合は何を変更する必要がありますか ):

入力ファイルが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    
11
Yaron

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秒です。

6
JoL