Запобігати різницю від перевірки нового рядка в кінці файлу


21

У мене є два великих дерева, які я хочу порівняти. Деякі файли в дереві відрізняються лише тим, що в одному є новий рядок в кінці, а в другому файлі відсутній цей новий рядок. Я хочу проігнорувати цей факт. Я спробував дзвонити diffтак:

diff --ignore-all-space -r <dir1> <dir2>

І це працює. Моя проблема полягає в тому, що вона також ігнорує інші відмінності (пов'язані з простором), які можуть бути важливими.

Підсумовуючи: Я просто хочу проігнорувати новий рядок на EOF. Це можливо за допомогою diff?

Відповіді:


17

В основному вам потрібно порівнювати два файли, умовно ігноруючи байт із заднім числом. Для цього не існує варіанту "diff" - але існує ряд способів, як це можна зробити (наприклад, на думку також приходить шестигранна різниця.)

Щоб використовувати "diff", вам в основному потрібно змінити файли, у яких відсутній новий рядок в кінці файлу, а потім порівняти. Ви можете створити тимчасовий каталог із зміненими файлами, або з невеликим сценарієм зробити це в пам'яті. (Що стосується переваги, залежить від уподобань, розміру файлу, кількості файлів ...)

Наприклад, нижче буде змінено вміст файлу (використовується sed -iдля зміни на місці, це просто друкується до stdout), щоб додати новий рядок, якщо його немає (або залишити файл незмінним, якщо вже є новий рядок):

sed -e '$a\'  file1.txt

І просто переглянути синтаксис 'diff' (повернення справжнього означає, що вони однакові, помилкові - це різні):

$ diff a/file1.txt   b/file1.txt  \
      && echo '** are same' || echo '** are different'
2c2
< eof
---
> eof
\ No newline at end of file
** are different

Перевірте, чи відрізняється лише пробіл:

$ diff --ignore-all-space  a/file1.txt   b/file1.txt \
     && echo '** are same' || echo '** are different'
** are same

В bash, ми можемо використовувати "sed" для маніпулювання вмістом файлу, коли він передається до "diff" (оригінальні файли залишаються незмінними):

$ diff <(sed -e '$a\' a/file1.txt) <(sed -e '$a\' b/file1.txt) \
     && echo '** are same' || echo '** are different'
** are same

Тепер все, що вам потрібно зробити, - це емуляція diff -rрекурсивного порівняння каталогів. Якщо порівнювати каталоги aта b, то для всіх файлів у a(наприклад, a/dir1/dir2/file.txt) вивести шлях до файлу до b(наприклад, b/dir1/dir2/file.txt) та порівняти:

$ for f in $( find a -type f  )
> do
>    diff <(sed -e '$a\' $f) <(sed -e '$a\' b/${f#*/})
> done

Трохи більш деталізована версія:

$ for f in $( find a -type f  )
> do
>   f1=$f
>   f2=b/${f#*/}
>   echo "compare: $f1 $f2"
>   diff <(sed -e '$a\' $f1) <(sed -e '$a\' $f2) \
>       && echo '** are same' || echo '** are different'
> done && echo '** all are same' || echo '** all are different'
compare: a/file1.txt b/file1.txt
** are same
compare: a/file2.txt b/file2.txt
** are same
** all are same

Ви можете, будь ласка, пояснити, що sed -e '$a\'саме робить? thx
törzsmókus

запустити sed, враховуючи наступний ( -e) скрипт / вираз, який відповідає кінці файлу ( $), і виконайте дію "додавання" (a \), але насправді не вказуйте жодного тексту (нічого після "\`), який продовжує додавати EOF / новий рядок до кінця файлу (лише якщо він відсутній).
Майкл

Дякую. Я ще не бачив a\ .
törzsmókus

1

Я вирішив проблему, додавши новий рядок до кожного з файлів і проігнорувавши порожні рядки у diff (опції -B). Це рішення може не відповідати вашому випадку використання, але може допомогти іншим:

echo >> $FILE1 
echo >> $FILE2
diff -B $FILE1 FILE2 

0

Переведіть висновок diffна grepкоманду, яка скидає повідомлення, яке ви не хочете бачити.


не добре. diff -r існує з результатом! = 0, якщо я не додаю --ignore-all-space. Щоб було зрозуміло: я хочу, щоб різниця ігнорувала нові рядки в EOF, і тільки в EOF. І я хочу, щоб він повідомив результат, який відповідає цим критеріям. Тобто, якщо файли у дереві відрізняються лише у новому рядку на EOF, це не повинно вважатись різницею, і, таким чином, diff має повернути 0.
dangonfast

0

Просто придумав інший підхід, який буде працювати для великих файлів (і все ще не копіює та не змінює оригінальні файли). Вам все одно доведеться емулювати рекурсивну траверсію каталогів (і це є ряд способів зробити це), але цей приклад не використовує "sed", а просто порівнює два файли, виключаючи останній байт, використовуючи cmp, наприклад,

$ cmp  a/file1.txt  b/file1.txt  && echo '** are same' || echo '** are different'
cmp: EOF on b/file1.txt
** are different

$ du -b a/file1.txt  b/file1.txt 
13  a/file1.txt
12  b/file1.txt

$ cmp  -n 12 a/file1.txt  b/file1.txt  && echo '** are same' || echo '** are different'
** are same

Ще проведіть цикл на всі файли в каталозі та для двох файлів a / file.txt та b / file.txt обчисліть більший розмір файлу та відніміть один, а потім зробіть двійковий diff ( cmp), використовуючи цю кількість байтів (також у баш):

(( bytes = $(du -b a/file.txt  b/file.txt  | sort -nr | head -1  | cut -f1) - 1 ))
cmp -n $bytes a/file.txt b/file.txt

Перекидання файлів буде таким самим, як і в іншій відповіді за допомогою sedі diff.


0

Відповідь проста.
Повідомлення про відсутній новий рядок знаходиться не у вихідному потоці, diffа у потоці помилок. Тож прихиліть його до нірвани, і ви зробите для добра

diff -rqEeB fileA fileB 2> /dev/null

diff повертає значення! = 0, якщо він знаходить відмінності, і я хочу перевірити це значення. Перенаправлення на / dev / null не змушує забувати цю різницю, тому значення, що повертається, є! = 0, чого я не хочу. Я хочу, щоб розглянути два файли були рівними, якщо єдиною різницею є останній новий рядок
dangonfast

-1

У diff comnad є прапор: --strip-trailing-crвиконайте саме те, що ви просили


-1. Ви пробували це? Це трактує /r/nяк /nі не має нічого спільного з додатковими /nбезпосередньо перед EOF.
Каміль Маціоровський

Я спробував це, і використав його для розрізнення файлів з різними dos / unix newline ... чи не правильно?
дхарман

Питання стосується лише ігнорування нового рядка лише в EOF (кінець файлу).
Каміль Маціоровський
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.