Empêcher diff de vérifier la nouvelle ligne à la fin du fichier


21

J'ai deux gros arbres que je veux comparer. Certains des fichiers de l'arborescence diffèrent simplement parce que l'un a une nouvelle ligne à la fin, et l'autre fichier n'a pas cette nouvelle ligne. Je veux ignorer ce fait. J'ai essayé d'appeler diffcomme ça:

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

Et cela fonctionne. Mon problème est qu'il ignore également d'autres différences (liées à l'espace), qui peuvent être importantes.

En résumé: je veux juste ignorer la nouvelle ligne à l'EOF. Est-ce possible avec diff?

Réponses:


17

Vous devez essentiellement comparer deux fichiers, en ignorant conditionnellement l'octet de fin. Il n'y a pas d'option 'diff' pour faire cela - mais il y a un certain nombre de façons de le faire (par exemple, la différence hexadécimale vient également à l'esprit.)

Pour utiliser 'diff', vous devez fondamentalement modifier les fichiers auxquels il manque la nouvelle ligne à la fin d'un fichier, puis comparer. Vous pouvez créer un répertoire temporaire avec les fichiers modifiés, ou avec un peu de script, cela pourrait être fait en mémoire. (La préférence dépend de la préférence, de la taille du fichier, du nombre de fichiers ...)

Par exemple, ce qui suit modifiera le contenu d'un fichier (utilisez sed -ipour modifier sur place, cela s'imprime simplement sur stdout) pour ajouter une nouvelle ligne s'il en manque une (ou laisser le fichier inchangé s'il y a déjà une nouvelle ligne):

sed -e '$a\'  file1.txt

Et juste pour revoir la syntaxe 'diff' (renvoyer true signifie qu'ils sont identiques, false signifie différent):

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

Vérifiez que seul l'espace blanc est différent:

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

En bash, nous pouvons utiliser 'sed' pour manipuler le contenu du fichier lorsqu'il est passé à 'diff' (les fichiers d'origine restent inchangés):

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

Il ne vous reste plus qu'à émuler diff -rpour comparer récursivement les répertoires. Si vous comparez les répertoires aet b, alors pour tous les fichiers dans a(par exemple, a/dir1/dir2/file.txt) dérivez le chemin vers le fichier dans b(par exemple, b/dir1/dir2/file.txt) et comparez:

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

Une version un peu plus verbeuse:

$ 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

pourriez-vous s'il vous plaît expliquer ce sed -e '$a\'que fait exactement? thx
törzsmókus

exécuter sed, étant donné le -escript / expression ( ) suivant , qui correspond à la fin du fichier ( $), et effectuer l'action "ajouter" (a \), mais ne spécifiez en fait aucun texte (rien après le `\`) qui va toujours ajouter un EOF / newline à la fin du fichier (seulement s'il est manquant).
michael

THX. Je ne l'ai pas a\ encore vu .
törzsmókus

1

J'ai résolu le problème en ajoutant une nouvelle ligne à chacun des fichiers et en ignorant les lignes vides dans le diff (option -B). Ces solutions peuvent ne pas convenir à votre cas d'utilisation, mais elles peuvent aider les autres:

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

0

Dirigez la sortie de diffvers une grepcommande qui supprime le message que vous ne souhaitez pas voir.


pas bon. diff -r existe avec result! = 0 si je n'ajoute pas --ignore-all-space. Pour être clair: je veux que diff ignore les sauts de ligne à EOF, et seulement à EOF. Et je veux qu'il rapporte un résultat qui correspond à ces critères. Autrement dit, si les fichiers dans l'arborescence diffèrent uniquement sur la nouvelle ligne à EOF, cela ne doit pas être considéré comme une différence, et donc diff doit retourner 0.
dangonfast

0

J'ai juste pensé à une approche différente, aussi, qui fonctionnera pour des fichiers plus volumineux (et ne copie toujours pas ou ne modifie pas les fichiers originaux). Vous devrez toujours émuler la traversée récursive du répertoire (et il existe plusieurs façons de le faire), mais cet exemple n'utilise pas 'sed', mais compare simplement deux fichiers, à l'exclusion du dernier octet, en utilisant cmp, par exemple,

$ 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

Faites toujours une boucle sur tous les fichiers du répertoire et pour deux fichiers a / file.txt et b / file.txt, calculez la plus grande taille de fichier et soustrayez-en un, puis faites un diff binaire ( cmp) en utilisant ce nombre d'octets (également dans frapper):

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

La boucle sur les fichiers serait la même que dans l'autre réponse en utilisant sedet diff.


0

La réponse est simple.
Le message concernant la nouvelle ligne manquante ne se trouve pas dans le flux de sortie de diffmais dans le flux d'erreur. Alors pliez-le au nirvana et vous avez terminé pour de bon

diff -rqEeB fileA fileB 2> /dev/null

diff renvoie une valeur! = 0 s'il trouve des différences et que je veux vérifier cette valeur. La redirection vers / dev / null ne fait pas oublier à diff cette différence, donc la valeur renvoyée est! = 0, ce que je ne veux pas. Je veux que diff considère deux fichiers égaux si la seule différence est la dernière nouvelle ligne
dangonfast

-1

Il y a un drapeau dans diff commnad: --strip-trailing-crqui fait exactement ce que vous avez demandé


-1. Avez-vous essayé cela? Il traite /r/ncomme /net n'a rien à voir avec un supplément /njuste avant l'EOF.
Kamil Maciorowski

J'ai essayé ceci, et je l'ai utilisé pour diff fichier avec différents newline dos / unix ... n'est-ce pas correct?
dharman

La question est d'ignorer la nouvelle ligne à EOF (fin de fichier) uniquement.
Kamil Maciorowski
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.