Basicamente, você precisa comparar dois arquivos, ignorando condicionalmente o byte à direita. Não há uma opção 'diff' para fazer isso - mas há várias maneiras de fazer isso (por exemplo, hex diff também vem à mente).
Para usar 'diff', você basicamente precisa modificar os arquivos que estão faltando a nova linha no final de um arquivo e comparar. Você pode criar um diretório temporário com os arquivos modificados ou, com um pouco de script, isso pode ser feito na memória. (O que é preferido depende da preferência, tamanho do arquivo, número de arquivos ...)
Por exemplo, o seguinte modifica o conteúdo de um arquivo (use sed -i
para modificar no local, isso apenas imprime em stdout) para adicionar uma nova linha se houver uma faltando (ou deixar o arquivo inalterado se já houver uma nova linha):
sed -e '$a\' file1.txt
E apenas para revisar a sintaxe 'diff' (retornar true significa que eles são iguais, false significa diferente):
$ diff a/file1.txt b/file1.txt \
&& echo '** are same' || echo '** are different'
2c2
< eof
---
> eof
\ No newline at end of file
** are different
Verifique se apenas o espaço em branco é diferente:
$ diff --ignore-all-space a/file1.txt b/file1.txt \
&& echo '** are same' || echo '** are different'
** are same
No bash, podemos usar 'sed' para manipular o conteúdo do arquivo, conforme é passado para 'diff' (os arquivos originais permanecem inalterados):
$ diff <(sed -e '$a\' a/file1.txt) <(sed -e '$a\' b/file1.txt) \
&& echo '** are same' || echo '** are different'
** are same
Agora tudo que você precisa fazer é emular diff -r
para comparar diretórios recursivamente. Se estiver comparando diretórios a
e b
, em seguida, para todos os arquivos em a
(por exemplo, a/dir1/dir2/file.txt
) , obtenha o caminho para o arquivo em b
(por exemplo, b/dir1/dir2/file.txt
) e compare:
$ for f in $( find a -type f )
> do
> diff <(sed -e '$a\' $f) <(sed -e '$a\' b/${f#*/})
> done
Uma versão um pouco mais detalhada:
$ 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\'
exatamente faz? thxsed
, dado o seguinte-e
script / expressão ( ), que corresponde ao final do arquivo ($
), e execute a ação "anexar" (a \), mas na verdade não especifique nenhum texto (nada após o `\`) que ainda adicionará um EOF / nova linha ao final do arquivo (somente se estiver ausente).a\
.Resolvi o problema adicionando uma nova linha a cada um dos arquivos e ignorando as linhas em branco no diff (opção
-B
). Essas soluções podem não ser adequadas para o seu caso de uso, mas podem ajudar outras pessoas:fonte
Canalize a saída de
diff
para umgrep
comando que descarta a mensagem que você não deseja ver.fonte
Também pensei em uma abordagem diferente, que funcionará para arquivos maiores (e ainda não copia ou modifica os arquivos originais). Você ainda teria que emular o percurso do diretório recursivo (e há várias maneiras de fazer isso), mas este exemplo não usa 'sed', mas apenas compara dois arquivos, excluindo o último byte, usando
cmp
, por exemplo,Ainda faça um loop sobre todos os arquivos no diretório e, para dois arquivos a / file.txt eb / file.txt, calcule o tamanho do arquivo maior e subtraia um, depois faça um diff binário (
cmp
) usando esse número de bytes (também em bater):Fazer um loop sobre os arquivos seria o mesmo que na outra resposta usando
sed
ediff
.fonte
A resposta é simples.
A mensagem sobre a nova linha ausente não está no fluxo de saída,
diff
mas no fluxo de erro. Então dobre-o para o nirvana e você estará pronto para semprefonte
Há uma bandeira no diff commnad:
--strip-trailing-cr
que faz exatamente o que você pediufonte
/r/n
como/n
e não tem nada a ver com extra/n
pouco antes do EOF.