outils de comparaison linux: créer une liste de fichiers modifiés


14

Comment créer une liste de fichiers modifiés par programmation à l'aide des outils de ligne de commande Linux? Je ne suis pas intéressé par la différence dans un fichier particulier (delta, patch). Je veux juste avoir une liste de fichiers nouveaux ou modifiés par rapport à la version précédente du produit. Pour que je puisse publier une nouvelle mise à jour de produit.

mise à jour: diff -qrne produit pas de sortie très pratique. La sortie de diff -qrdoit également être traitée. Y a-t-il une meilleure façon?


qu'est-ce qu'un exemple de sortie "pratique"?
frogstarr78

Réponses:


8

J'ai une approche simple pour cela: utilisez le mode de prévisualisation rsync:

rsync -aHSvn --delete old_dir/ new-dir/

Les fichiers qui sont affichés comme "à supprimer" par cette commande seront les "nouveaux" fichiers. Les autres qui doivent être transférés ont changé d'une manière ou d'une autre. Voir la page de manuel rsync pour plus de détails.


13

Vous pouvez utiliser l' outil diff : voir les options -q et -r

-q  --brief
Output only whether files differ.

-r  --recursive
Recursively compare any subdirectories found.

Exemple:

diff -qr dir1 dir2

Sortie absolument horrible et illisible, encombrée d'informations absurdes disant Only inqui apparaît même si les répertoires sont des copies idéales. J'avais besoin de comparer les modifications par rapport à une ancienne révision, et de finir par télécharger la révision entière dans un répertoire séparé, et d'utiliser des outils SVN standard pour comparer. Cela semble être la seule voie à suivre…
Hi-Angel

3

Le diffutilspackage comprend un lsdiffoutil. diff -uPassez simplement la sortie de à lsdiff:

diff -u --other-diff-options path1 path2 | lsdiff

Bonne suggestion, merci. Était dans le patchutilspackage pour moi (CentOS 5.x).
Steve Kehlet

Oui, le paquet patchutils pour Ubuntu / Debian aussi.
artfulrobot

1

Je toucherais simplement un fichier au moment de chaque mise à jour, puis vous pourrez trouver des fichiers qui ont été modifiés depuis avec find /tree/location -newer /last/update/file -print


1

Pour ne prendre que le nom des fichiers qu'ils ont modifiés, j'utilise cette commande:

diff -r dirt1 dir2 --brief | sed 's/^Only in \([^:]*\): /\1\//' | sed 's/^Files \(.*\) and .* differ/\1/'

Si vous devez exclure certains fichiers en tant que fichiers objets ou fichiers de bibliothèque, vous pouvez utiliser:

diff -r dirt1 dir2 --brief --exclude "*.o" --exclude "*.a" | sed 's/^Only in \([^:]*\): /\1\//' | sed 's/^Files \(.*\) and .* differ/\1/'

1

Pour créer une liste de fichiers nouveaux ou modifiés par programme, la meilleure solution que j'ai pu trouver consiste à utiliser rsync , sort et uniq :

(rsync -rcn --out-format="%n" old/ new/ && rsync -rcn --out-format="%n" new/ old/) | sort | uniq

Laissez-moi vous expliquer avec cet exemple: nous voulons comparer deux versions de dokuwiki pour voir quels fichiers ont été modifiés et lesquels ont été nouvellement créés.

Nous récupérons les goudrons avec wget et les extrayons dans les répertoires old/et new/:

wget http://download.dokuwiki.org/src/dokuwiki/dokuwiki-2014-09-29d.tgz
wget http://download.dokuwiki.org/src/dokuwiki/dokuwiki-2014-09-29.tgz
mkdir old && tar xzf dokuwiki-2014-09-29.tgz -C old --strip-components=1
mkdir new && tar xzf dokuwiki-2014-09-29d.tgz -C new --strip-components=1

L'exécution de rsync dans un sens peut manquer des fichiers nouvellement créés, comme le montre la comparaison de rsync et diff:

rsync -rcn --out-format="%n" old/ new/

donne la sortie suivante:

VERSION
doku.php
conf/mime.conf
inc/auth.php
inc/lang/no/lang.php
lib/plugins/acl/remote.php
lib/plugins/authplain/auth.php
lib/plugins/usermanager/admin.php

L'exécution de rsync dans un seul sens manque les fichiers nouvellement créés et dans l'autre sens, les fichiers supprimés sont manquants, comparez la sortie de diff:

diff -qr old/ new/

donne la sortie suivante:

Files old/VERSION and new/VERSION differ
Files old/conf/mime.conf and new/conf/mime.conf differ
Only in new/data/pages: playground
Files old/doku.php and new/doku.php differ
Files old/inc/auth.php and new/inc/auth.php differ
Files old/inc/lang/no/lang.php and new/inc/lang/no/lang.php differ
Files old/lib/plugins/acl/remote.php and new/lib/plugins/acl/remote.php differ
Files old/lib/plugins/authplain/auth.php and new/lib/plugins/authplain/auth.php differ
Files old/lib/plugins/usermanager/admin.php and new/lib/plugins/usermanager/admin.php differ

L'exécution de rsync dans les deux sens et le tri de la sortie pour supprimer les doublons révèlent que le répertoire data/pages/playground/et le fichier data/pages/playground/playground.txtont été manqués initialement:

(rsync -rcn --out-format="%n" old/ new/ && rsync -rcn --out-format="%n" new/ old/) | sort | uniq

donne la sortie suivante:

VERSION
conf/mime.conf
data/pages/playground/
data/pages/playground/playground.txt
doku.php
inc/auth.php
inc/lang/no/lang.php
lib/plugins/acl/remote.php
lib/plugins/authplain/auth.php
lib/plugins/usermanager/admin.php

rsync est exécuté avec ces arguments:

  • -r "recurse dans les répertoires",
  • -c pour comparer également des fichiers de taille identique et uniquement "sauter en fonction de la somme de contrôle, pas du temps et de la taille du mod",
  • -n "effectuer un essai sans aucune modification", et
  • --out-format="%n" à "afficher les mises à jour en utilisant le FORMAT spécifié", qui est "% n" ici pour le nom de fichier uniquement

La sortie (liste des fichiers) rsyncdans les deux directions est combinée et triée à l'aide de sort, et cette liste triée est ensuite condensée en supprimant tous les doublons avecuniq


0

Vous devriez obtenir le résultat souhaité en utilisant:

diff -r --brief dir1/ dir2/

0

Cela pourrait faire l'affaire:

compare_dirs()
{
    # Shows which files and directories exist in one directory but not both
    if [ $# -ne 2 ]
    then
        echo "Usage: compare_dirs dir1 dir2" >&2
        return 2
    fi
    for path
    do
        if [ ! -d "$path" ]
        then
            echo "Not a directory: $path" >&2
            return 1
        fi
    done
    comm -3 \
        <(cd -- "$1" && find . -printf '%P\0' | sort -z | quote_shell) \
        <(cd -- "$2" && find . -printf '%P\0' | sort -z | quote_shell)
}

0

Normalement, vous placez les fichiers dans une sorte de système de contrôle de version comme SubVersion ou git, car ceux-ci peuvent le faire à votre place.

Mais vous pouvez faire un script rapide avec une boucle for sur dir1, puis comparer chaque fichier avec celui de dir2. La boucle for peut regarder le code de sortie de diff pour savoir si les fichiers étaient différents.

Peut-être quelque chose comme ça:

for f in `(cd dir1 ; find .)`
do 
  diff $f ../dir2/$f
  if [ "$?" == "0" ]
  then 
    echo same
  else 
    echo diff: $f
  fi
done

Remarque: Le script n'est pas testé, donc l'exemple ci-dessus est "pseudocode inspiré de bash" ...


Prenons un autre essai mais avec git

Créez des exemples de fichiers pour jouer avec

mkdir -p dir1/test1/test11
mkdir -p dir1/test1/test12
mkdir -p dir1/test1/test13
echo "Test1" >> dir1/test1/test11/t1.txt
echo "Test2" >> dir1/test1/test12/t2.txt
echo "Test3" >> dir1/test1/test13/t3.txt

#And a dir to work in
mkdir gitdir

Entrez ensuite le dir et importez dir1

cd gitdir/
git init .
cp -r ../dir1/* .
git add .
git commit -m 'dir1'

Sortez et modifiez dir1 (pour qu'il devienne votre dir2)

cd ..
echo "Test2" > dir1/test1/test11/t1.txt

Ensuite, allez dans le répertoire git et importez le nouveau répertoire

cd gitdir/
cp -r ../dir1/* .

Maintenant, demandez à git ce qui a changé (avec la commande status)

git status -s

La sortie est une liste avec les changements, qui ressemble à ceci:

 M test1/test11/t1.txt

0

Vous seriez peut-être plus heureux avec quelque chose de différent. Essayez git.

Faites ceci comme exemple:

mkdir a
cd a
git init
touch b
git add . && git commit -m "Empty file"
git status
echo c >> b
git status
git add . && git commit -m "Full file"
git status

gitsuivra vos fichiers pour vous. La commande git statusvous montrera tous les fichiers qui ont été modifiés depuis le dernier commit.


0

Ceci est similaire à rsync: affiche quand le nouveau fichier sur la destination doit être écrasé (demandé plus tard, mais pas en double).

Comme indiqué dans la question, "diff -q -r" peut nécessiter un certain traitement pour être utile. La question ne précisait pas la forme de la sortie; les réponses donnent différents types de rapports.

rsyncest un outil utile à cet effet car il est beaucoup plus rapide que diff. Cependant, la solution suggérée par @nils est beaucoup plus détaillée (et répertorie plus de fichiers) que les différences réelles entre les anciennes / nouvelles arborescences de répertoires. Par exemple, en comparant cela avec le script que j'ai écrit pour cette réponse, et en exécutant les mêmes données,

  • La réponse @nils produit 605 lignes (apparemment parce qu'elle inclut des changements de répertoire ),
  • "diff -q -r" produit 352 lignes après plusieurs minutes de fonctionnement, et
  • mon script affiche 252 lignes ( les fichiers réels ont été modifiés, ajoutés ou supprimés)

Pour rendre diffcorrectement compte des nouveaux fichiers, vous avez également besoin de l' -Noption (que je ne vois dans aucune des réponses suggérées). Cependant, puisqu'il est beaucoup plus lent (ordres de grandeur) que rsync, l'amélioration de la production de ce dernier semble être la voie à suivre.

Lectures complémentaires


0

J'ai toujours été partial pour sha1sum (ou même md5sum; dans ce contexte, c'est assez sûr).

find . -type f -print0 | xargs -0 md5sum | sort -k2 > /tmp/before
# don't miss the "sort" in there; it's important

# (later)
find . -type f -print0 | xargs -0 md5sum | sort -k2 > /tmp/after
vimdiff /tmp/before /tmp/after
# or whatever diff tool you like, even "diff -u"

Parfois - comme si vous avez trop de fichiers renommés ou déplacés - le tri sur le premier champ et ensuite faire le diff pourrait aider, mais la plupart du temps c'est assez bien.

Notez que, par rapport à certaines des autres méthodes, cela présente l'avantage que vous n'avez pas besoin de conserver une copie des fichiers "avant"; seul le fichier de sortie md5sum.

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.