Найти строки из файла, которых нет в другом файле

У меня есть два файла (скажем a.txt и b.txt), оба из которых имеют список имен. Я уже запускал sort для обоих файлов.

Теперь я хочу найти строки из a.txt, которые отсутствуют в b.txt.

(Я потратил много времени, чтобы найти ответ на этот вопрос, поэтому документирую его для будущей справки)

Ответ 1

Команда, которую вы должны использовать, не diff, а comm

comm -23 a.txt b.txt

По умолчанию comm выводит 3 столбца: только слева, только справа. Переключатели -1, -2 и -3 подавляют эти столбцы.

Итак, -23 скрывает правый и оба столбца, показывая строки, которые появляются только в первом (левом) файле.

Если вы хотите найти строки, которые появляются в обоих, вы можете использовать -12, который скрывает только левый и правый столбцы, оставляя вас только с обоими столбцами.

Ответ 2

Простой ответ не сработал у меня, потому что я не понимал, что comm соответствует строке для строки, поэтому дубликаты строк в одном файле будут напечатаны как не существующие в другом. Например, если файл1 содержит:

Alex
Bill
Fred

И файл2 содержит:

Alex
Bill
Bill
Bill
Fred

Затем comm -13 file1 file2 выводит:

Bill
Bill

В моем случае я хотел знать только, что каждая строка в файле2 существовала в файле1, независимо от того, сколько раз эта строка встречалась в каждом файле.

Решение 1: используйте флаг -u (unique) для sort:

comm -13 <(sort -u file1) <(sort -u file2)

Решение 2: (первый "рабочий" ответ, который я нашел) из unix.stackexchange:

fgrep -v -f file1 file2

Обратите внимание, что если file2 содержит повторяющиеся строки, которые вообще не существуют в файле1, fgrep выводит каждую из повторяющихся строк. Также обратите внимание, что мои совершенно ненаучные тесты на одном ноутбуке для одного (довольно большого) набора данных показали, что решение 1 (с использованием comm) будет почти в 5 раз быстрее, чем решение 2 (используя fgrep).

Ответ 3

В случае, если файлы еще не отсортированы, вы можете использовать:

comm -23 <(sort a.txt) <(sort b.txt)

Ответ 4

Я не уверен, почему было сказано, что diff не должно использоваться. Я бы использовал его для сравнения двух файлов, а затем выводил только строки, которые находятся в левом файле, но не в правильном. Такие строки помечены diff с помощью <, поэтому достаточно grep этот символ в начале строки

diff a.txt b.txt  | grep \^\<