İki büyük dosyanın farkı


14

"Test1.csv" var ve içeriyor

200,400,600,800
100,300,500,700
50,25,125,310

ve test2.csv ve içeriyor

100,4,2,1,7
200,400,600,800
21,22,23,24,25
50,25,125,310
50,25,700,5

şimdi

diff test2.csv test1.csv > result.csv

farklı

diff test1.csv test2.csv > result.csv

Hangisinin doğru sıra olduğunu bilmiyorum ama başka bir şey istiyorum, yukarıdaki komutların her ikisi de

2 > 100,4,2,1,7
   3 2,3c3,5
   4 < 100,300,500,700
   5 < 50,25,125,310
   6 \ No newline at end of file
   7 ---
   8 > 21,22,23,24,25
   9 > 50,25,125,310

Ben sadece farkı çıktı istiyorum, bu yüzden results.csv böyle görünmelidir

100,300,500,700
100,4,2,1,7
21,22,23,24,25
50,25,700,5

Denedim diff -qve diff -sancak hile yapmadım. Düzen önemli değil, önemli olan sadece farkı görmek istiyorum, ne> ne de <veya boşluk.

grep -FvF büyük dosyalar üzerinde değil küçük dosyalar üzerinde hile yaptı

ilk dosya 5 milyondan fazla satır, ikinci dosya 1300'den fazla satır içeriyor.

bu nedenle results.csv ~ 4.998.700 satırla sonuçlanmalıdır

Ben de grep -F -x -v -f hangi işe yaramadı denedim .



1
@Zaman bağlantınızı gördüm ve ben eski bir üyeyim, bu yüzden kuralları biliyorum ama dikkatsiz, üzgünüm :) düzenliyordum ve yazının düzenlendiği bir pop-up gördüm, bu yüzden benim için çalıştım ve ben müteşekkir efendim.
Lynob

50,25,125,310her iki dosya için ortaktır ... bunu istediğiniz çıktıdan çıkarmanız gerekir ..
heemayl

Sipariş korunmalı mı?
kos

1
bir çeşit bilgi ile ne yapmak istediğinize bağlıdır, diff, IMO, bir yama yapmak içindir. Her halükarda, artık en iyi aracınızdan, diff, grep, awk veya perl'den eminim.
Panther

Yanıtlar:


21

Kulağa bir iş gibi geliyor comm:

$ comm -3 <(sort test1.csv) <(sort test2.csv)
100,300,500,700
    100,4,2,1,7
    21,22,23,24,25
    50,25,700,5

Açıklandığı gibi man comm:

   -1     suppress column 1 (lines unique to FILE1)

   -2     suppress column 2 (lines unique to FILE2)

   -3     suppress column 3 (lines that appear in both files)

Böylece, -3yalnızca dosyalardan birine özgü satırlar yazdırılacaktır. Ancak, bunlar içinde bulundukları dosyaya göre girintilidir. Sekmeyi kaldırmak için şunu kullanın:

$ comm -3 <(sort test1.csv) <(sort test2.csv) | tr -d '\t'
100,300,500,700
100,4,2,1,7
21,22,23,24,25
50,25,700,5

Bu durumda, dosyaları sıralamanıza bile gerek yoktur ve aşağıdakileri basitleştirebilirsiniz:

comm -3 test1.csv test2.csv | tr -d '\t' > difference.csv

Hattýndan sonra boşluklar sizi kandýrmadý 200,[...]ha? :)
kos

@kos no, önce dosyalardan sondaki boşlukları kaldırdım. OP dosyalarının aslında onlara sahip olmadığını varsaydım.
terdon

6

Proses ikamesi grepile kullanma bash:

$ cat <(grep -vFf test2.csv test1.csv) <(grep -vFf test1.csv test2.csv)
100,300,500,700
100,4,2,1,7
21,22,23,24,25
50,25,700,5

Çıkışı şu şekilde kaydetmek için results.csv:

cat <(grep -vFf test2.csv test1.csv) <(grep -vFf test1.csv test2.csv) >results.csv
  • <()olduğu bashproses ikame paterni

  • grep -vFf test2.csv test1.csv yalnızca benzersiz olan satırları bulacaktır test1.csv

  • grep -vFf test1.csv test2.csv yalnızca benzersiz olan satırları bulacaktır test2.csv

  • Sonunda sonuçları şöyle özetliyoruz: cat

Veya Oli'nin önerdiği gibi , komut gruplamasını da kullanabilirsiniz:

$ { grep -vFf test2.csv test1.csv; grep -vFf test1.csv test2.csv; }
100,300,500,700
100,4,2,1,7
21,22,23,24,25
50,25,700,5

Ya da birbiri ardına koşun, her ikisi de STDOUT'a yazdıklarından sonuçta eklenecekler:

$ grep -vFf test2.csv test1.csv; grep -vFf test1.csv test2.csv
100,300,500,700
100,4,2,1,7
21,22,23,24,25
50,25,700,5

1
Neden catiki yönlendirilmiş komut? Neden sadece diğerinden sonra koşmuyorsun? grep ... ; grep ...ya { grep ... ; grep ... ; }da kolektif çıktı ile bir şeyler yapmak istiyorsanız.
Oli

@Oli Teşekkürler .. bu harika bir fikir .. bunu düşünmedim ..
heemayl

4

Satırların sırası uygun değilse awkveya tuşlarını kullanın perl:

awk '{seen[$0]++} END {for (i in seen) {if (seen[i] == 1) {print i}}}' 1.csv 2.csv

grepOrtak hatları almak ve bunları filtrelemek için kullanın :

grep -hxvFf <(grep -Fxf 1.csv 2.csv) 1.csv 2.csv

Dahili grep ortak çizgileri alır, ardından harici grep bu ortak çizgilere uymayan çizgiler bulur.


Awk komutunuz yeniden uygulanır sort | uniq -u, bu da bir dosya yinelenen satırlar içerdiğinde yanlış yanıtı verir. Grep için, "iç" / "dış" değil, "iç" / "dış" derim.
Peter Cordes

@PeterCordes evet, öyle ve bunun yanlış sonuç olduğunu kim söylüyorsunuz?
muru

Sorunun tam olarak sorduğu şey değil, bu köşe durumunda yanlış. Birinin istediği şey olabilir, ancak ne awkyazdıracağınız ile neyin comm -3ve diffcevapların yazdırılacağı arasındaki farkı belirtmelisiniz .
Peter Cordes

@PeterCordes tekrar, bunu kim söylersin? OP istediklerini söyleyene kadar, çıktının bundan farklı olup olmadığını umursamıyorum comm -3. Neden hiçbir neden görmüyorum ben açıklamak gerekir. Bir notta düzenlemek istiyorsanız, çekinmeyin.
muru

OP farkı istediğini söyledi. Programınızın ürettiği her zaman bu değildir. Bir test çantası için aynı çıktıyı üreten, ancak tüm durumlar için yazılan açıklamayı karşılamayan bir program, başa çıkmayı gerektirir. Bunu söylemek için buradayım ve kim olduğumdan veya kim olduğunuzdan bağımsız olarak doğrudur. Bir not ekledim.
Peter Cordes

4

--*-line-format=...Seçeneklerini kullanındiff

diffTam olarak neye ihtiyacınız olduğunu söyleyebilirsiniz - aşağıda açıklanmıştır:

diff --old-line-format='%L' --new-line-format='%L' --unchanged-line-format='' f1.txt f2.txt

Farkın çıktısını bir printfsayı biçimine benzer şekilde çok ayrıntılı bir şekilde belirtmek mümkündür .

İlk dosyadaki test1.csvsatırlara "eski" satırlar, ikinci dosyadaki satırlara test2.csv"yeni" satırlar denir . Bu, diffbir dosyada nelerin değiştiğini görmek için kullanıldığında anlamlıdır .

İhtiyacımız olan seçenekler, "eski" satırların, "yeni" satırların ve "değişmeyen" satırların biçimini ayarlamak içindir.
İhtiyacımız olan biçimler çok basit:
Yeni ve eski olan değişen satırlar için yalnızca satırların metnini çıkarmak istiyoruz. %Lsatır metninin biçim sembolüdür.
Değişmeyen çizgiler için hiçbir şey göstermek istemiyoruz.

Bununla --old-line-format='%L'örnek verilerinizi kullanarak aşağıdaki gibi seçenekler yazabilir ve hepsini bir araya getirebiliriz:

$ diff --old-line-format='%L' --new-line-format='%L' --unchanged-line-format='' test1.csv test2.csv
100,4,2,1,7
100,300,500,700
21,22,23,24,25
50,25,700,5


Performansla ilgili notlar

Dosyalar farklı boyutlara sahip olduğundan, önemli değilse giriş dosyalarını değiştirmeye çalışın, iç işleyişleri diffbirinden diğerinden daha iyi işleyebilir. Daha iyi, daha az bellek veya daha az hesaplama gerektirir.

Kullanmak için bir optimizasyon seçeneği yoktur diffbüyük dosyalar ile: --speed-large-files. Dosya yapısı hakkında varsayımlar kullanır, bu nedenle davanıza yardımcı olup olmadığı açık değildir, ancak denemeye değer.

Biçimi seçenekleri açıklanmaktadır man diffunder --LTYPE-line-format=LFMT.


3

Siparişin korunması gerekmediğinden, basitçe:

sort test1.csv test2.csv | uniq -u
  • sort test1.csv test2.csv: birleşir ve sıralar test1.csvvetest2.csv
  • uniq -u: yalnızca kopya olmayan satırları yazdırır

Bir dosya iki kez bir satır içeriyorsa, diğer dosyada görünmeyen bu çalışmaz. Her iki olay da diffsonuçlanır.
Volker Siegel
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.