Saya punya file f1
:
line1
line2
line3
line4
..
..
Saya ingin menghapus semua baris yang ada di file lain f2
:
line2
line8
..
..
Saya mencoba sesuatu dengan cat
dan sed
, yang bahkan tidak mendekati apa yang saya inginkan. Bagaimana saya bisa melakukan ini?
Jawaban:
grep -v -x -f f2 f1
harus melakukan triknya.Penjelasan:
-v
untuk memilih garis yang tidak cocok-x
untuk mencocokkan hanya seluruh baris-f f2
untuk mendapatkan pola darif2
Sebagai gantinya, seseorang dapat menggunakan
grep -F
ataufgrep
untuk mencocokkan string tetap darif2
alih-alih pola (jika Anda ingin menghapus garis dengan cara "apa yang Anda lihat jika apa yang Anda dapatkan" daripada memperlakukan garisf2
sebagai pola regex).sumber
grep
. Jika preprocessesf2
dengan benar sebelum mulai mencari pencarian hanya akan memakan waktu O (n) waktu.Coba gunakan komunikasi (dengan asumsi f1 dan f2 "sudah diurutkan")
sumber
comm
apakah solusinya memiliki pertanyaan tidak menunjukkan bahwa barisf1
diurutkan yang merupakan prasyarat untuk digunakancomm
comm -2 -3 <(sort f1) <(sort f2)
Untuk mengecualikan file yang tidak terlalu besar, Anda dapat menggunakan array asosiatif AWK.
Outputnya akan berada dalam urutan yang sama dengan file "from-this.txt". The
tolower()
Fungsi membuatnya case-sensitive, jika Anda membutuhkan.Kompleksitas algoritmik mungkin adalah O (n) (exclude-these.txt size) + O (n) (from-this.txt size)
sumber
exclude-these.txt
kosong. Jawaban @ jona-christopher-sahnwaldt di bawah berfungsi dalam kasus ini. Anda juga dapat menentukan beberapa file misalnyaawk '{if (f==1) { r[$0] } else if (! ($0 in r)) { print $0 } } ' f=1 done.out failed.out f=2 all-files.out
Mirip dengan jawaban Dennis Williamson (sebagian besar perubahan sintaksis, misalnya mengatur nomor file secara eksplisit daripada
NR == FNR
triknya):awk '{if (f==1) { r[$0] } else if (! ($0 in r)) { print $0 } } ' f=1 exclude-these.txt f=2 from-this.txt
Mengakses
r[$0]
membuat entri untuk baris itu, tidak perlu menyetel nilai.Dengan asumsi awk menggunakan tabel hash dengan pencarian konstan dan waktu pembaruan konstan (rata-rata), kompleksitas waktu ini adalah O (n + m), di mana n dan m adalah panjang file. Dalam kasus saya, n adalah ~ 25 juta dan m ~ 14000. Solusi awk jauh lebih cepat daripada menyortir, dan saya juga lebih suka menyimpan pesanan aslinya.
sumber
f
lebih jelas dariNR == FNR
, tapi itu masalah selera. Penetapan ke dalam hash harus sangat cepat sehingga tidak ada perbedaan kecepatan yang dapat diukur antara kedua versi. Saya rasa saya salah tentang kompleksitas - jika pencarian konstan, pembaruan harus konstan juga (rata-rata). Saya tidak tahu mengapa saya pikir pembaruan akan menjadi logaritmik. Saya akan mengedit jawaban saya.awk '{if (f==1) { r[$0] } else if (! ($0 in r)) { print $0 } } ' f=1 empty.file done.out failed.out f=2 all-files.out
. Sedangkanawk
solusi lain gagal dengan file exclude kosong dan hanya dapat mengambil satu file.jika Anda memiliki Ruby (1.9+)
Yang memiliki kompleksitas O (N ^ 2). Jika Anda ingin peduli dengan kinerja, inilah versi lain
yang menggunakan hash untuk melakukan pengurangan, begitu juga kompleksitas O (n) (ukuran a) + O (n) (ukuran b)
berikut sedikit patokan, milik pengguna576875, tetapi dengan 100K baris, di atas:
diff
digunakan untuk menunjukkan tidak ada perbedaan antara 2 file yang dihasilkan.sumber
Beberapa perbandingan waktu antara berbagai jawaban lainnya:
sort f1 f2 | uniq -u
bahkan bukan perbedaan simetris, karena menghapus garis yang muncul beberapa kali di salah satu file.comm juga bisa digunakan dengan stdin dan di sini string:
sumber
Sepertinya pekerjaan yang cocok untuk shell SQLite:
sumber
Apakah Anda mencoba ini dengan sed?
sumber
Bukan jawaban 'pemrograman', tetapi inilah solusi cepat dan kotor: kunjungi saja http://www.listdiff.com/compare-2-lists-difference-tool .
Jelas tidak akan berfungsi untuk file besar tetapi itu berhasil untuk saya. Beberapa catatan:
sumber