İki dosyayı awk ile birleştirin


9

File1.txt

item1   carA
item2   carB
item3   carC
item4   platD
item5   carE

File2.txt

carA  platA
carB  platB
carC  platC
carE  platE

İstenen çıktı:

item1   platA
item2   platB
item3   platC
item4   platD
item5   platE

Nasıl yapabilirim?

Yanıtlar:


11

Aşağıdaki cevap, bazı ilgili değişikliklerle SO'daki benzer bir Soru ve Cevaplara dayanmaktadır :

$ 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

Fikir, indeksli bir karma harita oluşturmak ve bunu sözlük olarak kullanmaktır.

Yorumunuzda sorduğunuz 2. soru için ( ikinci sütunu file1.txtaltıncı sütun olacaksa nelerin değiştirilmesi gerekir ):

Giriş dosyası aşağıdaki gibi olacaksa 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

Aşağıdaki komut bunu yapar:

$ 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 - Yorumdaki ikinci sorunuzu da çözmek için cevabımı güncelledim. Sorunuzu cevapladıysam lütfen kabul edin.
Yaron

6

Söylediğini biliyorum awk, ama joinbu amaçla bir emir var ...

{
  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

joinBu satır olmasaydı ilk komutla yeterli olurdu :

item4   platD

Komut temelde şöyle der: ilk dosyanın ( -1 2) ikinci sütununa ve ikinci dosyanın ( ) ilk sütununa dayalı olarak birleşin ve ilk dosyanın ilk sütununu ve ikinci dosyanın ( -2 1) ikinci sütununu çıktılayın -o 1.1,2.2. Bu sadece eşleşen satırları gösterir. İkinci birleştirme komutu hemen hemen aynı şeyi söyler, ancak ilk dosyadan eşleştirilemeyen satırları ( -v 1) gösterir ve ilk dosyanın ilk sütununu ve ilk dosyanın ( -o 1.1,1.2) ikinci sütununu çıkarır . Sonra her ikisinin de çıktısını sıraladık. sort -k 1ilk sütuna sort -k 2göre sıralama, ikincisine göre sıralama anlamına gelir. Dosyaları geçirmeden önce birleştirme sütununa göre sıralamak önemlidir join.

Şimdi, sıralamayı iki kez yazdım, çünkü yardımcı olabilirsem dizinlerimi dosyalarla doldurmak istemiyorum. Ancak, David Foerster'in dediği gibi, dosyaların boyutuna bağlı olarak, dosyaları sıralamak ve her birini iki kez sıralamak için beklemek zorunda kalmadan önce kaydetmek isteyebilirsiniz. Boyutlar hakkında bir fikir vermek için, bilgisayarımda 1 milyon ve 10 milyon satır sıralamanın zamanı geldi:

$ 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

Bu 1 milyon satır için 1.5 saniye ve 10 milyon satır için 19 saniyedir.


Bu durumda, sıralanan giriş verilerinin (geçici) ara dosyalarda saklanması daha iyi olur çünkü sıralama önemsiz boyutlarda olmayan veri setleri için oldukça uzun sürer. Aksi takdirde +1.
David Foerster

@David İyi bir nokta. Şahsen, ara dosyalar oluşturmaktan gerçekten hoşlanmıyorum, ama aynı zamanda uzun süren süreçlerle de sabırsızım. "Önemsiz boyutta" ne olacağını merak ettim ve küçük bir kıyaslama yaptım ve önerinizle birlikte cevaba ekledim.
JoL

1 mio kayıt sıralamak makul modern masaüstü bilgisayarlarda yeterince hızlı. 2 büyüklükte 3 büyüklükte daha fazla şey ilginç olmaya başlar. Her durumda, geçen (gerçek) zaman ( %Ezaman formatında) hesaplama performansını ölçmek için daha az ilgi çekicidir. Kullanıcı modu CPU süresi ( %Uveya basitçe ayarlanmamış bir TIMEFORMATdeğişken) çok daha anlamlı olacaktır.
David Foerster

@David Farklı zamanlarda kullanım durumlarını pek bilmiyorum. Neden daha ilginç? Geçen zaman, aslında beklediğim zamanla çakışan zamandır. 1,5 saniyelik komut için 4,5 saniye alıyorum %U.
JoL

1
Geçen süre, aynı sistemde çalışan diğer görevlerde beklemek ve G / Ç isteklerini engellemek için harcanan zamandan etkilenir. (Kullanıcı) CPU zamanı değil. Genellikle, hesaplamalı bağlı algoritmaların hızını karşılaştırırken, G / Ç'yi göz ardı etmek ve diğer arka plan görevleri nedeniyle ölçüm hatalarından kaçınmak ister. Önemli soru "Bu algoritma bu veri kümesinde ne kadar hesaplama gerektiriyor?" "Bilgisayarım bu hesaplamanın tamamlanmasını beklerken tüm görevlerine ne kadar zaman harcadı?"
David Foerster
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.