В основном вам нужно сравнить два файла, условно игнорируя завершающий байт. Для этого нет опции 'diff' - но есть несколько способов, которыми это можно сделать (например, на ум приходит hex diff).
Чтобы использовать 'diff', вам необходимо изменить файлы, в которых отсутствует символ новой строки в конце файла, а затем сравнить. Вы можете создать временный каталог с измененными файлами, или с помощью небольшого количества сценариев это можно сделать в памяти. (То, что является предпочтительным, зависит от предпочтения, размера файла, количества файлов ...)
Например, следующее изменит содержимое файла (используйте sed -i
для изменения на месте, это просто печатает на стандартный вывод), чтобы добавить новую строку, если она отсутствует (или оставить файл без изменений, если уже есть новая строка):
sed -e '$a\' file1.txt
И просто для просмотра синтаксиса 'diff' (возвращение true означает, что они одинаковы, false означает разные):
$ 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\'
именно? thxsed
, используя приведенный ниже-e
скрипт / выражение ( ), соответствующий концу file ($
), и выполните действие «добавить» (a \), но на самом деле не указывайте никакого текста (ничего после `\`), который все еще собирается добавить EOF / newline в конец файла (только если он отсутствует).a\
.Я решил проблему, добавив новую строку в каждый из файлов и проигнорировав пустые строки в diff (опция
-B
). Эти решения могут не подходить для вашего случая использования, но могут помочь другим:источник
Труба выхода
diff
кgrep
команде , которая падает сообщение , которое вы не хотите видеть.источник
Просто подумал о другом подходе, который будет работать для больших файлов (и при этом не копировать и не изменять исходные файлы). Вам все равно придется эмулировать рекурсивный обход каталога (и есть несколько способов сделать это), но этот пример не использует «sed», а просто сравнивает два файла, исключая последний байт, используя
cmp
, например,По-прежнему перебирайте все файлы в каталоге, и для двух файлов a / file.txt и b / file.txt рассчитайте больший размер файла и вычтите один, а затем выполните двоичный анализ diff (
cmp
), используя это число байтов (также в Баш):Циклы по файлам будут такими же, как в другом ответе с использованием
sed
иdiff
.источник
Ответ прост.
Сообщение об отсутствующей новой строке находится не в потоке вывода,
diff
а в потоке ошибок. Так что согни его в нирвану, и вы сделали навсегдаисточник
В diff commnad есть флаг: он
--strip-trailing-cr
делает именно то, что вы просилиисточник
/r/n
как/n
и не имеет ничего общего с дополнительным/n
только перед EOF.