Чи є інструмент для отримання рядків в одному файлі, які не є в іншому?


110

Чи є інструмент, який може отримати рядки, який містить файл A, але файл B не має? Я міг би зробити трохи простий сценарій, наприклад, з perl, але якщо щось подібне вже існує, я з цього часу заощаджую свій час.



Відповіді:


159

Так. Стандартний grepінструмент пошуку файлів за текстовими рядками може використовуватися для віднімання всіх рядків в одному файлі від іншого.

grep -F -x -v -f fileB fileA

Це працює, використовуючи кожен рядок у fileB як візерунок ( -f fileB) та обробляючи його як звичайний рядок, який відповідає (а не звичайний регулярний вираз) ( -F). Ви змушуєте збіг відбуватись у всій лінії ( -x) та друкуєте лише ті рядки, які не відповідають ( -v). Тому ви друкуєте рядки у fileA, які не містять тих самих даних, що й будь-які рядки у fileB.

Мінус цього рішення полягає в тому, що він не враховує порядок рядків, і якщо у вашому введенні є дублікати рядків у різних місцях, ви можете не отримати те, що очікуєте. Рішенням цього є використання реального інструменту порівняння, такого як diff. Ви можете зробити це, створивши файл diff зі значенням контексту на 100% рядків у файлі, а потім розібрав його лише для рядків, які будуть видалені, якщо перетворити файл A у файл B. (Зверніть увагу, ця команда також видаляє diff форматування після отримання правильних ліній.)

diff -U $(wc -l < fileA) fileA fileB | sed -n 's/^-//p' > fileC

@ inderpreet99 Аргумент нижнього регістру -uнасправді приймає параметр числа, доки за ним не пробіл. Перевага способу, який я мав раніше, полягає в тому, що він буде працювати зі значенням або без нього, так що ви можете використовувати щось у тій підпрограмі підкоманд, яка не повертається. Верхня літера "-U", з іншого боку, вимагає аргументу.
Калеб

будьте обережні, Grep -f є O (N ^ 2) Я вважаю: stackoverflow.com/questions/4780203 / ...
rogerdpack

1
diffтрубопровід працює ласощі спасибі.
Феліпе Альварес

Щоб врахувати проблему сортування, ви можете використовувати підстановку процесу в команді для обробки кожного файлу раніше, ніж grepпотрібно. Приклад:grep -F -x -v -f <(sort fileB) <(sort fileA)
Тоні Чезаро

@TonyCesaro Це може спрацювати, якщо ваш набір даних не має конкретного порядку, а дублікати не потрібно враховувати. Перевагою використання diffє те, що положення у файлі враховується.
Калеб

57

Відповідь багато в чому залежить від типу та формату файлів, які ви порівнюєте.

Якщо файли, які ви порівнюєте, відсортовані текстові файли, то інструмент GNU, написаний Річардом Сталлманом та Девідеєм Маккензі, commможе викликати фільтрацію, яку ви шукаєте. Він входить до основних ядер.

Приклад

Скажімо, у вас є два такі файли:

$ cat a
1
2
3
4
5

$ cat b
1
2
3
4
5
6

Рядки у файлі b, які відсутні у файлі a:

$ comm <(sort a) <(sort b) -3
    6

1
+1 для згадки comm; на жаль, commпотрібні відсортовані файли
Arcege

11
так сортувати їх? comm <(сорт a) <(сорт b) -1 -2
Sirex

Це якийсь дивний синтаксис. <()? Це працює, і я розумію, але чи є назва цієї дивацтва?
mlissner

2
@mlissner <()також відомий як процес заміщення .
miku

1
commСпочатку був написаний приблизно в 1973 р. ким-то в Bell Labs, а не в rms. Ви маєте на увазі реалізацію GNU, яка надійшла набагато пізніше. Протягом багатьох років було багато різних реалізацій утиліт Unix.
Стефан Шазелас

32

від stackoverflow ...

comm -23 file1 file2

-23 пригнічує рядки, які знаходяться в обох файлах, або лише у файлі 2. Файли мають бути відсортовані (вони є у вашому прикладі), але якщо ні, спочатку переведіть їх через сортування ...

Дивіться сторінку людини тут


Це не працює для мене, з якої - то причини ...
Jan

@Jan ваші файли відсортовані? Як ви їх сортували?
JJS

8

Методи grep і comm (з сортуванням) займають багато часу для великих файлів. SiegeX і ghostdog74 поділилися двома чудовими методами awk для витягування рядків, унікальних для одного з двох файлів на Overflow Overck:

$ awk 'FNR==NR{a[$0]++}FNR!=NR && !a[$0]{print}' file1 file2

$ awk 'FNR==NR{a[$0]++;next}(!($0 in a))' file1 file2

2
Якщо ви робите це з величезними файлами, то обмеження пам’яті щодо завантаження величезного файлу в асоціативний масив буде непомірним.
Чарльз Даффі

4

Якщо файли великі і у вас немає спеціального замовлення на ваші записи, grep триває дуже багато часу. Швидка альтернатива була б

sort file1 > 1 
sort file2 > 2 
diff 1 2 | grep "\>" | sed -e 's/> //'

[file2-file1 результати на екрані, передача файлів тощо]

Зміна >до <отримають протилежне віднімання.rm 1 2


2

Ви також можете розглянути vimdiff, він підкреслює відмінності між файлами в редакторі vim


1
Але чи є простий спосіб автоматично зробити віднімання у Vimdiff?
Казарк
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.