farklı dosyaların iki sütununu karşılaştırın ve eşleşiyorsa yazdırın


16

Solaris 10 kullanıyorum ve bu yüzden -f'yi içeren grep seçenekleri çalışmıyor.

İki boru ile ayrılmış dosyam var:

file1:

abc|123|BNY|apple|
cab|234|cyx|orange|
def|kumar|pki|bird|

dosya 2:

abc|123|
kumar|pki|
cab|234

File1'in ilk iki sütununu file1 ile eşleştirmek istiyorsanız (ilk iki sütundaki file1'in tüm içeriğinde arama yapın) eşleşen file1 satırını yazdırırlar. Sonra dosya 2'nin ikinci satırını arayın ve bu şekilde devam edin.

Beklenen çıktı:

abc|123|BNY|apple|
cab|234|cyx|orange|

Sahip olduğum dosyalar yaklaşık 400.000 satır içeren çok büyük, bu yüzden yürütmeyi hızlı yapmak istiyorum.


Önde gelen boşlukları örneklerinizden kaldırdım, isterseniz lütfen düzenlemeyi geri alın. Boşlukların önemli olduğunu unutmayın, yalnızca gerçek dosyalarınızda varsa bunlara sahip olmalısınız.
terdon

GNU sürümünü kullanmayı deneyin grep, altında /usr/sfw/bin/ggrep. stackoverflow.com/questions/15259882/…
slm

Yanıtlar:


21

Awk bunun için tasarlandı:

$ awk -F'|' 'NR==FNR{c[$1$2]++;next};c[$1$2] > 0' file2 file1
abc|123|BNY|apple|
cab|234|cyx|orange|

açıklama

  • -F'|': alan ayırıcısını olarak ayarlar |.
  • NR==FNR: NR geçerli giriş satırı numarası ve FNR geçerli dosyanın satır numarasıdır. İkisi yalnızca 1. dosya okunurken eşit olacaktır.
  • c[$1$2]++; next: bu 1. dosyaysa, cdizideki ilk iki alanı kaydedin . Ardından, yalnızca 1. dosyaya uygulanacak şekilde bir sonraki satıra geçin.

  • c[$1$2]>0: else bloğu yalnızca bu ikinci dosyaysa yürütülür, bu nedenle bu dosyanın 1 ve 2 alanlarının önceden görülüp görülmediğini kontrol ederiz ( c[$1$2]>0) ve eğer olduysa satırı yazdırırız. İçinde awk, varsayılan eylem satırı yazdırmaktır, böylece c[$1$2]>0doğruysa, satır yazdırılır.


Alternatif olarak, Perl ile etiketlediğinizden:

perl -e 'open(A, "file2"); while(<A>){/.+?\|[^|]+/ && $k{$&}++};
         while(<>){/.+?\|[^|]+/ && do{print if defined($k{$&})}}' file1

açıklama

İlk satır açılacak file2, 2. |( .+?\|[^|]+) 'ye kadar olan her şeyi okuyacak ve bunu ( $&son maç operatörünün sonucu) %kkarmaya kaydedecektir .

İkinci satır dosya1'i işler, ilk iki sütunu ayıklamak ve bu sütunlar %kkarma içinde tanımlanmışsa satırı yazdırmak için aynı normal ifadeyi kullanır .


Yukarıdaki her iki yaklaşımın da dosya2'nin ilk 2 sütununu bellekte tutması gerekecektir. Sadece birkaç yüz bin hattınız varsa bu bir sorun olmamalı, ancak eğer böyle bir şey yapabilirsiniz

cut -d'|' -f 1,2 file2 | while read pat; do grep "^$pat" file1; done

Ama bu daha yavaş olacak.


Ancak bu işlemin tümü (ilk iki sütun) file2belleğe yüklenmeyecek mi?
Joseph R.

@terdon: awk -F'|' 'NR==FNR{c[$1$2]++;next};c[$1$2] > 0'daha kısa versiyonudur.
cuonglm

işe yaramaz ..
user68365

@ user68365: file2Yinelenen satırlar var mı?
cuonglm

NO yinelenen satır yok
user68365

1

bence

grep -Ff file2 file1

aradığınız şey bu. Verimli olmalı, ancak istediğiniz kadar doğru olacağından emin değilim. Eğer abc|123(örneğin) bir hat bulunur file1farklı sütunlarda, bu satır sıra basılacaktır. Bunun asla gerçekleşmeyeceğini garanti edebiliyorsanız, yukarıdaki satır çalışmalıdır.


Grep yeterli olmaz, çünkü abc | 123 bu dosyada bir yerde bulunabilir. Ayrıca solaris 10 kullanıyorum ve bu grep seçeneğini de kullanamıyorum.
user68365

2
@ user68365 lütfen sorunuzdaki tüm bilgileri açıklığa kavuşturun. Bize işletim sisteminizi söylemeniz ve yalnızca ilk 2 sütunu eşleştirmek istediğinizi belirtmeniz gerekir.
terdon

1

Sorunu SQL'de bir şekilde düşünmek istiyorsanız, kesinlikle ' q ' adlı bir aracı denemelisiniz :

$ q -d '|' "select f1.* from file1 f1 join file2 f2 on (f1.c1 = f2.c1 and f1.c2 = f2.c2)"

SQL sorgusuna aşina olup olmadığınızı anlamak daha açık ve kolaydır.


Şimdiye kadar en az şifreli çözümlerden biri için teşekkür ederim. İstediğim bu. Ama bu "q aracını"
Rolf

Çok kullanışlı bir araç.
ghilesZ

0
$  sed 's/^/\^/' 2.txt > temp.txt ; grep 1.txt -f temp.txt
abc|123|BNY|apple|
cab|234|cyx|orange|

1
Düzenlediğim ve soruda belirtildiği gibi, grep -f seçenekleri sistemimde çalışmıyor
user68365

Solaris 10, / usr / sfw / bin Use / usr / sfw / bin / sed ve / usr /
sfw
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.