Impedir que o diff verifique a nova linha no final do arquivo

21

Eu tenho duas árvores grandes, que eu quero comparar. Alguns dos arquivos na árvore diferem apenas porque um possui uma nova linha no final e o outro arquivo não possui essa nova linha. Eu quero ignorar esse fato. Eu tentei ligar diffassim:

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

E isso está funcionando. Meu problema é que ele também ignora outras diferenças (relacionadas ao espaço), que podem ser importantes.

Em resumo: eu quero ignorar a nova linha no EOF. Isso é possível com diff?

dangonfast
fonte

Respostas:

17

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 -ipara 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 -rpara comparar diretórios recursivamente. Se estiver comparando diretórios ae 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
Michael
fonte
você poderia explicar o que sed -e '$a\'exatamente faz? thx
törzsmókus 7/09/16
execute sed, dado o seguinte -escript / 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).
michael
THX. Eu ainda não vi a\ .
törzsmókus 8/09/16
1

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:

echo >> $FILE1 
echo >> $FILE2
diff -B $FILE1 FILE2 
Jakob
fonte
0

Canalize a saída de diffpara um grepcomando que descarta a mensagem que você não deseja ver.

David Schwartz
fonte
não é bom. diff -r existe com resultado! = 0 se eu não adicionar --ignore-all-space. Para ser claro: eu quero que o diff ignore as novas linhas no EOF, e somente no EOF. E quero que ele relate um resultado que corresponda a esse critério. Ou seja, se os arquivos na árvore diferem apenas na nova linha no EOF, que não deve ser considerada uma diferença, e assim diff deve retornar 0.
dangonfast
0

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,

$ 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

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):

(( 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

Fazer um loop sobre os arquivos seria o mesmo que na outra resposta usando sede diff.

Michael
fonte
0

A resposta é simples.
A mensagem sobre a nova linha ausente não está no fluxo de saída, diffmas no fluxo de erro. Então dobre-o para o nirvana e você estará pronto para sempre

diff -rqEeB fileA fileB 2> /dev/null
yunzen
fonte
diff retorna um valor! = 0 se encontrar diferenças e eu quero verificar esse valor. Redirecionar para / dev / null não faz com que diff se esqueça dessa diferença; portanto, o valor retornado é! = 0, o que eu não quero. Quero diff considerar dois arquivos iguais se a única diferença é o último de nova linha
dangonfast
-1

Há uma bandeira no diff commnad: --strip-trailing-crque faz exatamente o que você pediu

dharman
fonte
-1. Você já tentou isso? Trata /r/ncomo /ne não tem nada a ver com extra /npouco antes do EOF.
Kamil Maciorowski
Eu tentei isso e usei-o para o arquivo diff com diferentes dos / unix newline ... não está correto?
Dharman
A questão é ignorar a nova linha no EOF (final do arquivo).
Kamil Maciorowski 10/10