Результат сравнения двух файлов с переключенными строками говорит о том, что дважды пропущена одна и та же строка


28

Я пытаюсь понять команду linux diff для двух файлов, строки которых просто перестановки друг друга, но не в состоянии получить вывод, который он генерирует. Рассмотрим три команды ниже:

[myPrompt]$ cat file1
apples
oranges
[myPrompt]$ cat file2 
oranges
apples
[myPrompt]$ diff file1 file2
1d0
< apples
2a2
> apples

Может кто-нибудь объяснить вышеупомянутый загадочный вывод из diff.

  1. Почему в выводе вообще нет упоминания об «апельсинах»?
  2. Что 1d0и 2a2означает?

Из этого ответа я понимаю, что:

«<» означает, что строка отсутствует в file2, а «>» означает, что строка отсутствует в file1

НО это не объясняет, почему апельсины отсутствуют в выводе.


12
Поскольку orangesэто самая большая общая часть между двумя файлами, то, что вы получите, является кратчайшим способом выразить разницу между этими двумя файлами.
Стефан Шазелас

10
И если вы хотите более читаемый вывод, просто используйте diff -u file1 file2вместо этого. Это называется «унифицированный формат». Первоначальный формат diff должен был быть очень компактным, но унифицированные diff должны быть более удобочитаемыми.
Godlygeek

4
@godlygeek Илиdiff -y file1 file2
user80551

Ответы:


27

Чтобы понять отчет, помните, что он diffносит предписывающий характер и описывает, какие изменения необходимо внести в первый файл ( file1), чтобы сделать его таким же, как и второй файл ( file2).

В частности, dв 1d0означает удалить, а aв 2a2означает добавить .

Таким образом:

  • 1d0означает, что строка 1 должна быть удалена в file1( apples). 0в 1d0строке означает, что они были бы во втором файле ( file2), если бы они не были удалены. Это означает, что при переходе file2к file1(назад) добавляется строка 1 file1после строки 0 of file2.
  • 2a2средство добавления второй линии ( oranges) от file2к ныне второй линии file1(после удаления первой строки в file1, orangesперешли на линию 1)

что 0внутри 1d0?
Компьютерщик

@ Посмотри на мои правки
хаос

1
@Geek Но будьте осторожны, это может создать узлы в мозге =)
хаос

что, действительно, начал делать узлы :-)
Geek

13

Рассмотрим эти файлы:

file1:

# cat file1
apples
pears
oranges
peaches

file2:

# cat file2
oranges
apples
peaches
ananas
banana

Как diffработает, учитывая это на основе заказа:

  1. diffчитает первый блок строк file1и file2и пытается найти равные строки:

      file1        file2        differences on left (<) or right side (>)
      apples                   <apples
      pears                    <pears 
      -------------------------------
    ->oranges    ->oranges
      peaches      apples
                   peaches
                   ananas
                   banana
    
  2. Теперь он пропустит все строки, которые равны в обоих файлах, что как раз orangesв этом случае:

      file1        file2        differences on left (<) or right side (>)
      apples                   <apples
      pears                    <pears 
      oranges      oranges
      -------------------------------
    ->peaches    ->apples
                   peaches
                   ananas
                   banana
    
  3. Теперь найдите другой набор похожих строк и распечатайте различия:

      file1        file2        differences on left (<) or right side (>)
      apples                   <apples
      pears                    <pears 
      oranges      oranges
                   apples      >apples
      -------------------------------
    ->peaches    ->peaches
                   ananas
                   banana
    
  4. Пропустить подобные строки

      file1        file2        differences on left (<) or right side (>)
      apples                   <apples
      pears                    <pears 
      oranges      oranges
                   apples      >apples
      peaches      peaches
      -------------------------------
    ->           ->ananas
                   banana
    
  5. Найдите одинаковые строки, если это возможно, и выведите различия:

    line_file1    file1    line_file2    file2        differences on left (<) or right side (>)
             1    apples                              <apples 
             2    pears                               <pears 
             3    oranges           1    oranges
                                    2    apples       >apples
             4    peaches           3    peaches
                                    4    ananas       >ananas
                                    5    banana       >banana
             -----------------------------------------------
    

Теперь, если я сделаю diff file1 file2:

# diff file1 file2
1,2d0
< apples
< pears
3a2
> apples
4a4,5
> ananas
> banana

Теперь просто объяснить, что diffозначает вывод:

Сделать file1равным file2:

  • 1,2d0: Удалить ( d) линии 1-2от file1и изменить линию 0из file2соответственно
  • 3a2: Append ( a) к линии 3от file1линии 2изfile2
  • 4a4,5: Append к линии 4из file1линий 4-5отfile2

diffсравнивает file1с file2построчно и устанавливает различия во временной памяти. После того , file1 равным file2 до первого вхождения строки в file1, который также происходит в file2, все линии, которые равны до тех пор , пока разница не упоминаются, часто обозначается как ---. В этом случае есть только одна похожая строка, которая есть oranges. Обратите внимание, что я сказал file1равно file2, поэтому file1рассматривается относительно, file2а не наоборот.

Выходные данные относятся к первому данному файлу, в данном случае file1.


2
Мне не нравится первоначальное объяснение: applesвстречается в обоих файлах также.
ИЛИ Mapper

1
@ORMapper Я изменил объяснение. Теперь это звучит более четко / лучше :)?
полим

Не совсем, на данный момент вы написали "есть только одна похожая строка, которая есть oranges". Неправильно: на самом деле есть две линии, которые не только похожи , но абсолютно идентичны . Один из них читает oranges, другой читает apples. Кроме того, ваше объяснение (чисто на основе порядка) противоречит комментарию Стефана к вопросу (основанному на длине) - кто прав?
ИЛИ Mapper

@ORMapper Вы забыли «В этом случае» и строки до этого. Я имел в виду, что на этом шаге есть только одна похожая строка. Я просто добавлю пример к своему ответу, чтобы его можно было лучше понять.
полим

1
@ORMapper Также вы можете привести пример, который показывает, что основанный на длине ответ является правильным?
полим

8

Там они:

$ diff file1 file2
1d0
< apples
2a2
> apples
$ diff file2 file1
1d0
< oranges
2a2
> oranges

8

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

Например: 1d0 <(удалить) означает, что яблоки необходимо удалить из 1-й строки file1, а 2a2 >(добавить) означает, что яблоки необходимо добавить во file22-ю строку, чтобы можно было сопоставить оба файла.

Документация, доступная в, info diffобъясняет это далее больше:

Отображение различий без контекста

«Нормальный» diffформат вывода показывает каждый кусок различий без какого-либо окружающего контекста. Иногда такой вывод является наиболее ясным способом увидеть, как изменились строки, без беспорядка соседних неизмененных строк (хотя вы можете получить аналогичные результаты с контекстом или унифицированными форматами, используя 0 строк контекста). Однако этот формат больше не используется для рассылки исправлений; для этой цели формат контекста и унифицированный формат являются превосходящими. Обычный формат используется по умолчанию для совместимости со старыми версиями diffи стандартом POSIX. Используйте --normalопцию, чтобы явно выбрать этот формат вывода.

Подробное описание нормального формата

Обычный формат вывода состоит из одного или нескольких блоков различий; каждый блок показывает одну область, где файлы отличаются. Обычные фрагменты формата выглядят так:

 CHANGE-COMMAND
 < FROM-FILE-LINE
 < FROM-FILE-LINE...
 ---
 > TO-FILE-LINE
 > TO-FILE-LINE...

Существует три типа команд изменения. Каждый из них состоит из номера строки или разделенного запятыми диапазона строк в первом файле, одного символа, указывающего тип вносимого изменения, и номера строки или разделенного запятыми диапазона строк во втором файле. Все номера строк являются исходными номерами строк в каждом файле. Типы команд изменения:

LaR Добавьте строки в диапазоне R второго файла после строки L первого файла. Например, 8a12,15означает добавить строки 12-15 файла 2 после строки 8 файла 1; или, если файл 2 изменяется в файл 1, удалить строки 12-15 файла 2.

FcT Замените строки в диапазоне F первого файла на строки в диапазоне T второго файла. Это как комбинированное добавление и удаление, но более компактное. Например, 5,7c8,10означает изменить строки 5-7 файла 1, чтобы они читались как строки 8-10 файла 2; или, если файл 2 изменяется на файл 1, измените строки 8-10 файла 2 на строки 5-7 файла 1.

RdL Удалить строки в диапазоне R из первого файла; строка L - это место, где они появились бы во втором файле, если бы они не были удалены. Например, 5,7d3означает удалить строки 5-7 файла 1; или, если файл 2 изменяется в файл 1, добавить строки 5-7 файла 1 после строки 3 файла 2.

Смотрите также:


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

В примере:

$ diff -y file1 file2
apples                                <
oranges                             oranges
                                  > apples

$ diff -u file1 file2
@@ -1,2 +1,2 @@
-apples
 oranges
+apples
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.