Як я можу отримати різний показ лише доданих та видалених рядків? Якщо diff не може це зробити, який інструмент може?


69

Як я можу отримати різний показ лише доданих та видалених рядків? Якщо diff не може це зробити, який інструмент може?


2
Вам потрібно краще визначити, що ви маєте на увазі під додаванням та видаленням. Зокрема, може змінюватися лінія? Якщо так, як ви хочете, щоб змінена лінія оброблялася? Якщо ви робите строго орієнтовану перевірку ліній, зміна рядка ідентична старому рядку, що видаляється, і новому рядку додається. Наприклад, як слід обробляти лінію, яка розділена навпіл? Як змінилися два 1 рядки? Змінено 2 рядки? Видалено 1 рядок і додано 2 рядки? Якщо ви не зможете гарантувати, що рядки ніколи не змінюватимуться, просто додайте та видаляйте, я думаю, що це приречено на провал без кращих визначень.
Крістофер Кашелл

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

Ви можете шукати comm.
Дженні Д

@ChristopherCashell, Він означає ігнорувати порядок сортування; типово поширена проблема. Зазвичай це робиться шляхом попереднього сортування сегментів (ліній) з кожної сторони, перш ніж зробити типовий розл.
Печер'є

@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, а третя колонка містить рядки, загальні для обох файлів.

Ці стовпці suppressable з -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

Наступна команда покаже рядки, вилучені з а або додані до b:

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

вихід:

B-ONLY
A-ONLY

Ця дещо інша команда покаже рядки, вилучені з a.txt:

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

вихід:

A-ONLY

Нарешті, ця команда покаже рядки, додані до a.txt

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

вихід

B-ONLY

2

Ось що відрізняється за замовчуванням ... Можливо, вам потрібно додати кілька прапорів, щоб ігнорувати пробіли?

diff -b -B

слід ігнорувати порожні рядки та різну кількість пробілів.


1
Ні, він також показує ЗМІНЕНІ рядки (рядки, що мають символ або чотири різних). Я хочу, щоб лінії існували лише зліва або справа.
C. Ross

2
Ви можете стверджувати, що різні версії файлу ЗМІНІ існують лише зліва або справа.
Маркдрайтон

2
Немає ніякого способу для розмаїття (чи будь-якого іншого інструменту) надійно сказати, що є зміною, а що - видаленим рядком, заміненим новим рядком.
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 не може надійно працювати у всіх випадках.
Mikko Rantalainen

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-bet between-two-files-in- linux

Тестовано в Ubuntu 18.04.


-1

Файл1:

text670_1
text067_1
text067_2

Файл2:

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.