Anda dapat mencapai ini dengan mengontrol pemformatan baris lama / baru / tidak berubah dalam diff
output GNU :
diff --new-line-format="" --unchanged-line-format="" file1 file2
File input harus disortir agar ini berfungsi. Dengan bash
(dan zsh
) Anda dapat mengurutkan di tempat dengan penggantian proses <( )
:
diff --new-line-format="" --unchanged-line-format="" <(sort file1) <(sort file2)
Dalam baris baru dan tidak berubah di atas ditekan, sehingga hanya diubah (yaitu garis yang dihapus dalam kasus Anda) adalah output. Anda juga dapat menggunakan beberapa diff
pilihan yang solusi lain tidak menawarkan, seperti -i
mengabaikan kasus, atau berbagai pilihan spasi ( -E
, -b
, -v
dll) untuk pencocokan kurang ketat.
Penjelasan
Opsi --new-line-format
, --old-line-format
dan --unchanged-line-format
biarkan Anda mengontrol cara diff
memformat perbedaan, mirip dengan printf
penentu format. Opsi-opsi ini memformat masing-masing baris baru (ditambahkan), lama (dihapus) dan tidak berubah . Menyetel satu untuk mengosongkan "" mencegah keluaran dari jalur semacam itu.
Jika Anda terbiasa dengan format diff terpadu , Anda dapat membuatnya sebagian dengan:
diff --old-line-format="-%L" --unchanged-line-format=" %L" \
--new-line-format="+%L" file1 file2
The %L
specifier adalah garis yang bersangkutan, dan kami awalan masing-masing dengan "+" "-" atau "", seperti diff -u
(catatan bahwa itu hanya perbedaan output, itu tidak memiliki ---
+++
dan @@
garis-garis di bagian atas setiap perubahan dikelompokkan). Anda juga dapat menggunakan ini untuk melakukan hal-hal lain yang bermanfaat seperti jumlah setiap baris dengan %dn
.
The diff
Metode (bersama dengan saran lain comm
dan join
) hanya menghasilkan output yang diharapkan dengan diurutkan masukan, meskipun Anda dapat menggunakan <(sort ...)
untuk mengurutkan di tempat. Berikut awk
skrip sederhana (nawk) (terinspirasi oleh skrip yang ditautkan ke dalam jawaban Konsolebox) yang menerima file input yang dipesan secara sewenang-wenang, dan menampilkan baris yang hilang sesuai urutannya pada file1.
# output lines in file1 that are not in file2
BEGIN { FS="" } # preserve whitespace
(NR==FNR) { ll1[FNR]=$0; nl1=FNR; } # file1, index by lineno
(NR!=FNR) { ss2[$0]++; } # file2, index by string
END {
for (ll=1; ll<=nl1; ll++) if (!(ll1[ll] in ss2)) print ll1[ll]
}
Ini menyimpan seluruh konten file1 baris demi baris dalam array yang diindeks nomor-baris ll1[]
, dan seluruh konten file2 baris demi baris dalam array asosiatif yang diindeks baris-konten ss2[]
. Setelah kedua file dibaca, beralihlah ll1
dan gunakan in
operator untuk menentukan apakah baris dalam file1 ada di file2. (Ini akan memiliki output yang berbeda dengan diff
metode ini jika ada duplikat.)
Jika file-file tersebut cukup besar sehingga menyimpan keduanya menyebabkan masalah memori, Anda dapat menukar CPU dengan memori dengan hanya menyimpan file1 dan menghapus kecocokan sepanjang jalan saat file2 dibaca.
BEGIN { FS="" }
(NR==FNR) { # file1, index by lineno and string
ll1[FNR]=$0; ss1[$0]=FNR; nl1=FNR;
}
(NR!=FNR) { # file2
if ($0 in ss1) { delete ll1[ss1[$0]]; delete ss1[$0]; }
}
END {
for (ll=1; ll<=nl1; ll++) if (ll in ll1) print ll1[ll]
}
Di atas menyimpan seluruh isi file1 dalam dua array, satu diindeks dengan nomor baris ll1[]
, satu diindeks oleh konten baris ss1[]
. Kemudian saat file2 dibaca, setiap baris yang cocok dihapus dari ll1[]
dan ss1[]
. Pada akhirnya baris yang tersisa dari file1 adalah output, mempertahankan urutan asli.
Dalam hal ini, dengan masalah seperti yang disebutkan, Anda juga dapat membagi dan menaklukkan menggunakan GNU split
(pemfilteran adalah ekstensi GNU), dijalankan berulang dengan potongan file1 dan membaca file2 sepenuhnya setiap kali:
split -l 20000 --filter='gawk -f linesnotin.awk - file2' < file1
Perhatikan penggunaan dan penempatan -
makna stdin
pada gawk
baris perintah. Ini disediakan oleh split
dari file1 dalam potongan 20.000 baris per-doa.
Untuk pengguna pada sistem non-GNU, ada hampir pasti coreutils GNU paket Anda dapat memperoleh, termasuk di OSX sebagai bagian dari Apel Xcode alat yang menyediakan GNU diff
, awk
, meskipun hanya POSIX / BSD split
daripada versi GNU.
awk 'NR==FNR{a[$0];next}!($0 in a)' file2 file1 > out.txt