Zasadniczo musisz porównać dwa pliki, warunkowo ignorując końcowy bajt. Nie ma opcji „diff”, aby to zrobić - ale istnieje wiele sposobów, aby to zrobić (np. Przychodzi na myśl również hex diff).
Aby użyć „diff”, musisz po prostu zmodyfikować pliki, które nie mają nowej linii na końcu pliku, a następnie porównać. Możesz utworzyć katalog tymczasowy ze zmodyfikowanymi plikami lub przy odrobinie skryptu można to zrobić w pamięci. (Wybór preferowanego zależy od preferencji, rozmiaru pliku, liczby plików ...)
Na przykład: zmodyfikuje zawartość pliku (użyj sed -i
do modyfikacji w miejscu, to po prostu drukuje na standardowe wyjście), aby dodać nowy wiersz, jeśli go brakuje (lub pozostaw plik bez zmian, jeśli już jest nowy wiersz):
sed -e '$a\' file1.txt
I tylko w celu przejrzenia składni „diff” (zwracanie true oznacza, że są takie same, false oznacza różne):
$ diff a/file1.txt b/file1.txt \
&& echo '** are same' || echo '** are different'
2c2
< eof
---
> eof
\ No newline at end of file
** are different
Sprawdź, czy tylko białe znaki są różne:
$ diff --ignore-all-space a/file1.txt b/file1.txt \
&& echo '** are same' || echo '** are different'
** are same
W bash możemy użyć „sed” do manipulowania zawartością pliku, który jest przekazywany do „diff” (oryginalne pliki pozostały niezmienione):
$ diff <(sed -e '$a\' a/file1.txt) <(sed -e '$a\' b/file1.txt) \
&& echo '** are same' || echo '** are different'
** are same
Teraz wystarczy naśladować diff -r
rekurencyjne porównywanie katalogów. W przypadku porównywania katalogów a
i b
, to dla wszystkich plików a
(na przykład a/dir1/dir2/file.txt
) nie czerpią ścieżkę do pliku w b
(na przykład b/dir1/dir2/file.txt
) i porównać:
$ for f in $( find a -type f )
> do
> diff <(sed -e '$a\' $f) <(sed -e '$a\' b/${f#*/})
> done
Nieco bardziej pełna wersja:
$ 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\'
dokładnie robi? thxsed
, biorąc pod uwagę następujący-e
skrypt / wyrażenie, które pasuje do końca pliku ($
), i wykonaj akcję „append” (a \), ale tak naprawdę nie określaj tekstu (nic po `\`), który nadal doda EOF / nowy wiersz na końcu pliku (tylko jeśli go brakuje).a\
.Rozwiązałem problem, dodając nowy wiersz do każdego pliku i ignorując puste linie w diff (opcja
-B
). Te rozwiązania mogą nie być odpowiednie dla twojego przypadku użycia, ale mogą pomóc innym:źródło
Potokuj wyjście
diff
dogrep
polecenia, które upuszcza komunikat, którego nie chcesz widzieć.źródło
Pomyślałem też o innym podejściu, które będzie działać dla większych plików (i nadal nie kopiuje ani nie modyfikuje oryginalnych plików). Nadal będziesz musiał emulować przechodzenie przez katalog rekurencyjny (istnieje wiele sposobów, aby to zrobić), ale ten przykład nie używa „sed”, ale po prostu porównuje dwa pliki, z wyłączeniem ostatniego bajtu, używając
cmp
np.Nadal zapętlaj wszystkie pliki w katalogu, a dla dwóch plików a / file.txt i b / file.txt, oblicz większy rozmiar pliku i odejmij jeden, a następnie wykonaj diff binarny (
cmp
) używając tej liczby bajtów (również w grzmotnąć):Pętle nad plikami byłyby takie same jak w innych odpowiedziach przy użyciu
sed
idiff
.źródło
Odpowiedź jest prosta.
Komunikat o brakującym nowym wierszu nie znajduje się w strumieniu wyjściowym,
diff
ale w strumieniu błędów. Więc zgnij to do nirwany, a skończysz na dobreźródło
W diff commnad znajduje się flaga:
--strip-trailing-cr
która robi dokładnie to, o co prosiłeśźródło
/r/n
jak/n
i nie ma nic wspólnego z dodatkowymi/n
tuż przed EOF.