Как я могу заставить diff показывать только добавленные и удаленные строки? Если diff не может этого сделать, какой инструмент может?


69

Как я могу заставить diff показывать только добавленные и удаленные строки? Если diff не может этого сделать, какой инструмент может?


2
Вам нужно лучше определить, что вы подразумеваете под добавлением и удалением. В частности, может ли линия измениться? Если да, то как вы хотите, чтобы измененная строка была обработана? Если вы выполняете строго строчно-ориентированную проверку, изменение строки идентично удалению старой строки и добавлению новой строки. Например, как он должен обрабатывать строку, которая разделена на две части? Как две 1 строки изменились? 2 строки изменились? 1 строка удалена и 2 строки добавлены? Если вы не можете гарантировать, что строки никогда не изменятся, просто будут добавлены и удалены, я думаю, что это обречено на провал без лучших определений.
Кристофер Кэшелл

Я нахожу вопрос довольно неясным. Но можно ответить хотя бы на одну интерпретацию вопросаdiff A B | grep '^[<>]'
kasperd


@ChristopherCashell, он означает игнорировать порядок сортировки; типично распространенная проблема. Обычно это делается путем сортировки сегментов (линий) с каждой стороны перед выполнением типичного сравнения.
Pacerier

@Pacerier, ты уверен в этом? Или ты угадаешь? Ничего о сортировке или порядке поиска не упоминается и не намекается в вопросе. В его нынешнем виде вопрос не ясен и может быть истолкован по-разному. Не зная точно, о чем он спрашивает, мы делаем предположения и предлагаем решения, которые могут или не могут решить реальную проблему. Кроме того, оригинальный комментарий автора к одному из ответов предполагает, что это не связано с сортировкой. Это имеет отношение к значению «добавлено и удалено» против «изменено».
Кристофер Кэшелл

Ответы:


82

Попробуй комм

Еще один способ взглянуть на это:

  • Показать строки, которые существуют только в файле a: (то есть, что было удалено из a)

    comm -23 a b
    
  • Показать строки, которые существуют только в файле b: (то есть, что было добавлено в b)

    comm -13 a b
    
  • Показать строки, которые существуют только в одном или другом файле: (но не оба)

    comm -3 a b | sed 's/^\t//'
    

(Предупреждение: если в файле aесть строки, начинающиеся с TAB, он (первый TAB) будет удален из выходных данных.)

Только отсортированные файлы

ПРИМЕЧАНИЕ. Оба файла должны быть отсортированы для commправильной работы. Если они еще не отсортированы, вы должны отсортировать их:

sort <a >a.sorted
sort <b >b.sorted
comm -12 a.sorted b.sorted

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


5
просто хотел добавить, что оба файла должны быть отсортированы (с учетом регистра), чтобы это решение дало правильные результаты
marmor

1
На достаточно современных оболочках вы можете отсортировать в линию что-то вродеcomm -12 <(sort a) <(sort b)
Джошуа Хубер

14

commможет делать то, что вы хотите. С его справочной страницы:

ОПИСАНИЕ

Сравните отсортированные файлы FILE1 и FILE2 построчно.

Без опций выведите три столбца. Первый столбец содержит строки, уникальные для FILE1, второй столбец содержит строки, уникальные для FILE2, а третий столбец содержит строки, общие для обоих файлов.

Эти столбцы подавляются с -1, -2и -3соответственно.

Пример:

[root@dev ~]# cat a
common
shared
unique

[root@dev ~]# cat b
common
individual
shared

[root@dev ~]# comm -3 a b
    individual
unique

И если вы просто хотите уникальные строки и не волнует, в каком файле они находятся:

[root@dev ~]# comm -3 a b | sed 's/^\t//'
individual
unique

Как говорится в справочной странице, файлы должны быть отсортированы заранее.


9

Чтобы показать добавления и удаления без контекста, номера строк, +, -, <,>! и т.д., вы можете использовать diff следующим образом:

diff --changed-group-format='%<%>' --unchanged-group-format='' a.txt b.txt 

Например, даны два файла:

a.txt

Common
Common
A-ONLY
Common

b.txt

Common
B-ONLY
Common
Common

Следующая команда покажет строки, удаленные из a или добавленные в b:

diff --changed-group-format='%<%>' --unchanged-group-format='' a.txt b.txt 

выход:

B-ONLY
A-ONLY

Эта немного другая команда покажет строки, удаленные из .txt:

diff --changed-group-format='%<' --unchanged-group-format='' a.txt b.txt 

выход:

A-ONLY

Наконец, эта команда покажет строки, добавленные в .txt

diff --changed-group-format='%>' --unchanged-group-format='' a.txt b.txt 

выход

B-ONLY

2

Это то, что делает diff по умолчанию ... Может быть, вам нужно добавить несколько флагов, чтобы игнорировать пробелы?

diff -b -B

следует игнорировать пустые строки и различное количество пробелов.


1
Нет, он также показывает ИЗМЕНЕННЫЕ строки (строки, которые имеют один или четыре символа). Я хочу строки, которые существуют только слева или справа.
К. Росс

2
Вы можете утверждать, что разные версии файла CHANGED существуют только слева или справа.
Маркдрайтон

2
У diff (или любого другого инструмента) нет возможности надежно определить, что является изменением и что удаленная строка заменяется новой строкой.
Cian

1
Технически, diff обрабатывает «измененную» строку так, как если бы исходная строка была удалена, а новая строка была добавлена ​​... так что технически она показывает только добавленные и удаленные строки.
KFro

2

Нет, на diffсамом деле не показывает различия между двумя файлами так, как можно подумать. Он создает последовательность команд редактирования для инструмента, который patchможно использовать для изменения одного файла в другой.

Сложность любой попытки сделать то, что вы ищете, состоит в том, как определить, что представляет собой линию, которая изменилась, по сравнению с удаленной, за которой следует добавленная. Также, что делать, когда строки добавляются, удаляются и меняются рядом друг с другом.


Мои мысли точно. Какой процент символов в строке должен измениться, чтобы считать его новым вместо модификации оригинала? Технически, даже если у вас есть один общий символ, вы можете считать его «изменением» вместо удаления и вставки.
Камил Кисиэль

1
Прошло много времени с тех пор, как я посмотрел на diffисточники, но я, кажется, помню все виды вращений, чтобы отслеживать, где два файла совпадают, чтобы оставаться синхронизированными, и я думаю, что есть предел для отказа в зависимости от того, как далеко друг от друга линии есть. Но я не помню ни одного совпадения внутри строки, кроме (необязательно) свернутого пробела или игнорирования регистра. Или (возможно) слова на это влияют. В любом случае, это все, patchи vgrep просто приходит на прогулку. Может быть. Во вторник.
Деннис Уильямсон

2

Инструменты визуального сравнения объединяют два файла, так что сегмент с одинаковым количеством строк, но разным содержанием будет считаться измененным сегментом. Полностью новые линии между совпадающими сегментами считаются добавленными сегментами.

Так же работает инструмент командной строки sdiff , который показывает параллельное сравнение двух файлов в терминале. Измененные строки разделены | характер. Если строка существует только в файле A, <используется как символ-разделитель. Если строка существует только в файле B,> используется в качестве разделителя. Если в файлах нет символов <и>, вы можете использовать это для отображения только добавленных строк:

sdiff A B | grep '[<>]'

2

Спасибо senarvi, ваше решение (за которое не голосовали) фактически дало мне ТОЧНО то, что я хотел, после того, как искал целую вечность на тонне страниц.

Используя ваш ответ, вот что я придумал, чтобы получить список вещей, которые были изменены / добавлены / удалены. В этом примере используются 2 версии файла / etc / passwd и выводится имя пользователя для соответствующих записей.

#!/bin/bash
sdiff passwd1 passwd2 | grep '[|]' | awk -F: '{print "changed: " $1}'
sdiff passwd1 passwd2 | grep '[<]' | awk -F: '{print "deleted: " $1}'
sdiff passwd1 passwd2 | grep '[>]' | awk -F\> '{print $2}' | awk -F: '{print "added: " $1}'

Обратите внимание, что различие между «строка была изменена» и «строка была удалена, а другая строка была добавлена ​​под или над ней» является семантической. Универсальный текстовый инструмент сравнения не может разделять эти случаи. В результате ваш ответ на основе sdiff не может надежно работать во всех случаях.
Микко Ранталайнен,

0

Я нахожу эту конкретную форму часто полезной:

diff --changed-group-format='-%<+%>' --unchanged-group-format='' f g

Пример:

printf 'a\nb\nc\nd\ne\nf\ng\n' > f
printf 'a\nB\nC\nd\nE\nF\ng\n' > g
diff --old-line-format=$'-%l\n' \
     --new-line-format=$'+%l\n' \
     --unchanged-line-format='' \
     f g

Выход:

-b
-c
+B
+C
-e
-f
+E
+F

Таким образом, он показывает старые строки с, -за которыми сразу следует соответствующая новая строка с +.

Если бы мы удалили C:

printf 'a\nb\nd\ne\nf\ng\n' > f
printf 'a\nB\nC\nd\nE\nF\ng\n' > g
diff --old-line-format=$'-%l\n' \
     --new-line-format=$'+%l\n' \
     --unchanged-line-format='' \
     f g

это выглядит так:

-b
+B
+C
-e
-f
+E
+F

Формат задокументирован по адресу man diff:

       --line-format=LFMT
              format all input lines with LFMT`

а также:

       LTYPE is 'old', 'new', or 'unchanged'.
              GTYPE is LTYPE or 'changed'.

а также:

              LFMT (only) may contain:

       %L     contents of line

       %l     contents of line, excluding any trailing newline

       [...]

Похожий вопрос: https://stackoverflow.com/questions/15384818/how-to-get-the-difference-only-additions-between-two-files-in-linux

Проверено в Ubuntu 18.04.


-1

File1:

text670_1
text067_1
text067_2

File2:

text04_1
text04_2
text05_1
text05_2
text067_1
text067_2
text1000_1

Использование:

diff -y file1 file2

Это показывает две колонки для соответствующих файлов.

Выход:

text670_1                           
                                  > text04_1
                                  > text04_2
                                  > text05_1
                                  > text05_2
text067_1                           text67_1
text067_2                           text67_2
                                  > text1000_1
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.