Gabungkan dua file dengan awk

9

File1.txt

item1   carA
item2   carB
item3   carC
item4   platD
item5   carE

File2.txt

carA  platA
carB  platB
carC  platC
carE  platE

Output yang diinginkan:

item1   platA
item2   platB
item3   platC
item4   platD
item5   platE

Bagaimana saya bisa melakukannya?

pawana
sumber

Jawaban:

11

Jawaban di bawah ini didasarkan pada T&J serupa di SO dengan beberapa modifikasi yang relevan:

$ 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

Idenya adalah untuk membuat peta hash dengan indeks, dan menggunakannya sebagai kamus.

Untuk pertanyaan kedua, Anda bertanya dalam komentar Anda ( apa yang harus diubah jika kolom kedua file1.txtakan menjadi kolom keenam ):

Jika file input akan seperti 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

Perintah berikut akan melakukannya:

$ 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    
Yaron
sumber
1
@ Pamana - Saya telah memperbarui jawaban saya untuk juga menyelesaikan pertanyaan kedua Anda dalam komentar. Jika saya sudah menjawab pertanyaan Anda, mohon terima .
Yaron
6

Saya tahu Anda berkata awk, tetapi ada joinperintah untuk tujuan ini ...

{
  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

Itu sudah cukup dengan joinperintah pertama jika bukan karena baris ini:

item4   platD

Perintah pada dasarnya mengatakan: join berdasarkan kolom kedua dari file pertama ( -1 2), dan kolom pertama dari file kedua ( -2 1), dan output kolom pertama dari file pertama dan kolom kedua dari file kedua ( -o 1.1,2.2). Itu hanya menunjukkan garis yang dipasangkan. Perintah gabungan kedua mengatakan hal yang hampir sama, tetapi dikatakan untuk menunjukkan baris dari file pertama yang tidak dapat dipasangkan ( -v 1), dan menampilkan kolom pertama dari file pertama dan kolom kedua dari file pertama ( -o 1.1,1.2). Kemudian kami mengurutkan hasil dari keduanya. sort -k 1berarti mengurutkan berdasarkan kolom pertama, dan sort -k 2berarti mengurutkan berdasarkan yang kedua. Penting untuk mengurutkan file berdasarkan kolom bergabung sebelum meneruskannya join.

Sekarang, saya menulis penyortiran dua kali, karena saya tidak suka mengotori direktori saya dengan file jika saya dapat membantu. Namun, seperti yang dikatakan David Foerster, tergantung pada ukuran file, Anda mungkin ingin mengurutkan file dan menyimpannya terlebih dahulu agar tidak perlu menunggu untuk mengurutkan masing-masing dua kali. Untuk memberikan gambaran tentang ukuran, inilah waktu yang diperlukan untuk mengurutkan 1 juta dan 10 juta garis di komputer saya:

$ 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

Itu 1,5 detik untuk 1 juta baris, dan 19 detik untuk 10 juta baris.

JoL
sumber
Dalam hal ini akan lebih baik untuk menyimpan data input yang diurutkan dalam file perantara (sementara) karena penyortiran membutuhkan waktu yang cukup lama untuk set data berukuran non-trivial. Kalau tidak +1.
David Foerster
@ David Jelas ini poin bagus. Secara pribadi, saya benar-benar tidak suka harus membuat file perantara, tapi saya juga tidak sabar dengan proses yang berjalan lama. Saya bertanya-tanya apa itu "ukuran sepele" akan, dan jadi saya membuat tolok ukur kecil, dan menambahkannya ke jawaban bersama dengan saran Anda.
JoL
Untuk mengurutkan 1 catatan mio cukup cepat pada komputer desktop yang cukup modern. Dengan 2 lebih dari 3 urutan besarnya lebih banyak hal mulai menjadi menarik. Dalam setiap kasus waktu yang berlalu (nyata) ( %Eformat waktu) kurang menarik untuk mengukur kinerja komputasi. Mode pengguna Waktu CPU ( %Uatau hanya TIMEFORMATvariabel yang tidak disetel ) akan jauh lebih bermakna.
David Foerster
@ David Saya tidak terlalu terbiasa dengan kasus penggunaan untuk waktu yang berbeda. Mengapa lebih menarik? Waktu yang berlalu adalah apa yang bertepatan dengan waktu yang sebenarnya saya tunggu. Untuk perintah 1,5 detik, saya mendapatkan 4,5 detik dengan %U.
JoL
1
Waktu yang berlalu dipengaruhi oleh waktu yang dihabiskan untuk menunggu tugas-tugas lain yang berjalan pada sistem yang sama dan memblokir permintaan I / O. (Pengguna) Waktu CPU tidak. Biasanya ketika membandingkan kecepatan algoritma terikat komputasi seseorang ingin mengabaikan I / O dan menghindari kesalahan pengukuran karena tugas latar belakang lainnya. Pertanyaan penting adalah "Berapa banyak perhitungan yang dibutuhkan algoritma ini pada set data itu?" alih-alih "Berapa banyak waktu yang dihabiskan komputer saya untuk semua tugasnya sambil menunggu perhitungan itu selesai?"
David Foerster