Сравнивайте два файла построчно и генерируйте разницу в другом файле - PullRequest
108 голосов
/ 28 декабря 2010

Я хочу сравнить файл1 с файлом2 и создать файл3, содержащий строки в файле1, которых нет в файле2.

Ответы [ 11 ]

195 голосов
/ 28 декабря 2010

diff (1) - не ответ, но comm (1) -.

NAME
       comm - compare two sorted files line by line

SYNOPSIS
       comm [OPTION]... FILE1 FILE2

...

       -1     suppress lines unique to FILE1

       -2     suppress lines unique to FILE2

       -3     suppress lines that appear in both files

So

comm -2 -3 file1 file2 > file3

Входные файлы должны быть отсортированы. Если это не так, сначала отсортируйте их. Это можно сделать с помощью временного файла или ...

comm -2 -3 <(sort file1) <(sort file2) > file3

при условии, что ваша оболочка поддерживает подстановку процессов (bash делает).

46 голосов
/ 28 декабря 2010

Утилита Unix diff предназначена именно для этой цели.

$ diff -u file1 file2 > file3

См. Руководство и Интернет для вариантов, различных форматов вывода и т. Д.

20 голосов
/ 28 декабря 2010

Учтите это:
файл a.txt:

abcd
efgh

файл b.txt:

abcd

Вы можете найти разницу с:

diff -a --suppress-common-lines -y a.txt b.txt

Вывод будет:

efgh 

Вы можете перенаправить вывод в выходной файл (c.txt), используя:

diff -a --suppress-common-lines -y a.txt b.txt > c.txt

Это ответит на ваш вопрос:

"... который содержит строки в файле1, которые отсутствует в файле 2. "

7 голосов
/ 28 декабря 2010

Иногда diff - это утилита, которая вам нужна, но иногда join более подходит. Файлы должны быть предварительно отсортированы или, если вы используете оболочку, которая поддерживает подстановку процессов, такую ​​как bash, ksh или zsh, вы можете выполнить сортировку на лету.

join -v 1 <(sort file1) <(sort file2)
5 голосов
/ 11 июня 2014

Попробуйте

sdiff file1 file2

Обычно это работает намного лучше для меня. Вы можете отсортировать файлы заранее, если порядок строк не важен (например, некоторые текстовые конфигурационные файлы).

Например,

sdiff -w 185 file1.cfg file2.cfg
3 голосов
/ 01 августа 2016

Если вам нужно решить эту проблему с помощью coreutils, то ответ будет хорошим:

comm -23 <(sort file1) <(sort file2) > file3

Вы также можете использовать sd (stream diff), который не требует сортировки или замены процесса и поддерживает бесконечные потоки, например:

cat file1 | sd 'cat file2' > file3

Вероятно, не так уж много пользы в этом примере, но все же рассмотрим его; в некоторых случаях вы не сможете использовать comm, ни grep -F, ни diff.

Вот blogpost Я писал о разнесении потоков на терминале, который вводит sd.

2 голосов
/ 30 декабря 2015

Уже много ответов, но ни один из них не идеален ИМХО. Ответ Танатоса оставляет несколько лишних символов в строке, а ответ Сорпигала требует, чтобы файлы были отсортированы или предварительно отсортированы, что может быть недостаточно при любых обстоятельствах.

Я думаю, что лучший способ получить строки, которые отличаются и ничем иным (без дополнительных символов, без переупорядочения), это сочетание diff, grep и awk (или аналогичных).

Если строки не содержат «<», короткая однострочная строка может быть: </p>

diff urls.txt* | grep "<" | sed 's/< //g'

но это удалит каждый экземпляр "<" (меньше, чем пробел) из строк, что не всегда нормально (например, исходный код). Самый безопасный вариант - использовать awk: </p>

diff urls.txt* | grep "<" | awk '{for (i=2; i<NF; i++) printf $i " "; print $NF}'

Этот однострочный дифференциал обоих файлов, затем отфильтровывает вывод diff в стиле ed, а затем удаляет завершающий "<", который добавляет diff. Это работает, даже если строки содержат некоторые символы «<». </p>

1 голос
/ 17 апреля 2019

Пока нет решения grep?

  • строк, которые существуют только в файле2:

    grep -Fxvf file1 file2 > file3
    
  • строк, которые существуюттолько в файле1:

    grep -Fxvf file2 file1 > file3
    
  • строк, которые существуют в обоих файлах:

    grep -Fxf file1 file2 > file3
    
1 голос
/ 19 июля 2017
diff a1.txt a2.txt | grep '> ' | sed 's/> //' > a3.txt

Я попробовал почти все ответы в этой теме, но ни один не был завершен.После нескольких следов выше одного работал на меня. diff даст вам разницу, но с некоторыми нежелательными специальными чарами.где вы фактическая разница строк начинается с '>'.поэтому следующий шаг - grep строки начинаются с '>' и затем удаляются так же с sed .

1 голос
/ 28 декабря 2010

Используйте утилиту Diff и извлекайте только строки, начинающиеся с <в выводе </p>

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...