strumenti diff linux: crea un elenco di file modificati


14

Come faccio a creare un elenco di file modificati a livello di codice utilizzando gli strumenti da riga di comando di Linux? Non mi interessa la differenza in alcun file particolare (delta, patch). Voglio solo avere un elenco di file nuovi o modificati rispetto alla versione precedente del prodotto. In modo da poter pubblicare un nuovo aggiornamento del prodotto.

aggiornamento: diff -qrnon produce output molto conveniente. Anche l'output di diff -qrdeve essere elaborato. C'è un modo migliore?


qual è un esempio di output "conveniente"?
frogstarr78,

Risposte:


8

Ho un approccio semplice per questo: usa la modalità rsync-preview:

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

I file che vengono mostrati come "da eliminare" da quel comando saranno i "nuovi" file. Gli altri che devono essere trasferiti sono cambiati in qualche modo. Vedi la pagina man di rsync per ulteriori dettagli.


13

Puoi usare il diff toool: vedi le opzioni -q e -r

-q  --brief
Output only whether files differ.

-r  --recursive
Recursively compare any subdirectories found.

Esempio:

diff -qr dir1 dir2

Uscita assolutamente orribile e illeggibile, ingombra di informazioni senza senso Only inche dicono che appare anche se le directory sono copie ideali. Avevo bisogno di confrontare le modifiche con una vecchia revisione, e alla fine scaricare l'intera revisione in una directory separata e utilizzare gli strumenti SVN standard per confrontare. Questa sembra l'unica strada da percorrere ...
Hi-Angel,

3

Il diffutilspacchetto include uno lsdiffstrumento. Basta passare l'output di diff -ua lsdiff:

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

Buon consiglio, grazie. Era nel patchutilspacchetto per me (CentOS 5.x).
Steve Kehlet,

Sì, pacchetto patchutils anche per Ubuntu / Debian.
artfulrobot

1

Vorrei solo toccare un file al momento di ogni aggiornamento, e quindi puoi trovare i file che sono stati modificati da allora con find /tree/location -newer /last/update/file -print


1

Per prendere solo il nome dei file che hanno cambiato, uso questo comando:

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

Se è necessario escludere alcuni file come file oggetto o file di libreria, è possibile utilizzare:

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

1

Per creare un elenco di file nuovi o modificati a livello di programmazione, la soluzione migliore che ho potuto trovare è usare rsync , sort e uniq :

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

Lasciatemi spiegare con questo esempio: vogliamo confrontare due versioni di dokuwiki per vedere quali file sono stati modificati e quali sono stati appena creati.

Prendiamo i tars con wget e li estraiamo nelle directory old/e 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'esecuzione di rsync in un modo potrebbe perdere i file appena creati come il confronto tra rsync e diff mostra qui:

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

produce il seguente output:

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

Eseguendo rsync solo in una direzione mancano i file appena creati e viceversa mancherebbero i file eliminati, confrontare l'output di diff:

diff -qr old/ new/

produce il seguente output:

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'esecuzione di rsync in entrambi i modi e l'ordinamento dell'output per rimuovere i duplicati rivela che inizialmente la directory data/pages/playground/e il file non data/pages/playground/playground.txtsono stati rilevati:

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

produce il seguente output:

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 viene eseguito con questi argomenti:

  • -r "ricorrere alle directory",
  • -c per confrontare anche file di dimensioni identiche e solo "salta in base al checksum, non a mod-time e dimensioni",
  • -n per "eseguire una corsa di prova senza apportare modifiche" e
  • --out-format="%n" a "output aggiornamenti usando il FORMATO specificato", che è "% n" qui solo per il nome del file

L'output (elenco di file) rsyncin entrambe le direzioni viene combinato e ordinato utilizzando sort, e questo elenco ordinato viene quindi condensato rimuovendo tutti i duplicati conuniq


0

Dovresti ottenere il risultato desiderato usando:

diff -r --brief dir1/ dir2/

0

Questo potrebbe fare il trucco:

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

Normalmente metti i file in un qualche tipo di sistema di controllo della versione come SubVersion o git, dal momento che quelli possono farlo immediatamente.

Ma potresti fare uno script veloce con un ciclo for su dir1 e quindi confrontare ogni file con quello in dir2. Il ciclo for può guardare il codice di uscita da diff per sapere se i file erano diversi.

Forse qualcosa del genere:

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

Nota: lo script non è testato, quindi l'esempio sopra è "pseudocodice ispirato a bash" ...


Facciamo un altro tentativo, ma con git

Crea alcuni file di esempio con cui giocare

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

Quindi immettere la directory e importare dir1

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

Esci e modifica dir1 (in modo che diventi il ​​tuo dir2)

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

Quindi vai nella directory git e importa la nuova directory

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

Ora chiedi a git cosa è cambiato (con il comando status)

git status -s

L'output è un elenco con le modifiche, che assomiglia a questo:

 M test1/test11/t1.txt

0

Forse saresti più felice con qualcosa di diverso. Prova git.

Fallo come esempio:

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

gitseguirà i tuoi file per te. Il comando git statusti mostrerà tutti i file che sono stati modificati dall'ultimo commit.


0

Questo è simile a rsync: mostra quando il file più recente sulla destinazione deve essere sovrascritto (richiesto in seguito, sebbene non sia un duplicato).

Come indicato nella domanda, "diff -q -r" potrebbe richiedere un po 'di elaborazione per essere utile. La domanda non specificava la forma dell'output; le risposte forniscono diversi tipi di rapporti.

rsyncè uno strumento utile a questo scopo perché è molto più veloce di diff. Tuttavia, la soluzione suggerita da @nils è molto più dettagliata (ed elenca più file) delle effettive differenze tra i vecchi / nuovi alberi di directory. Ad esempio, confrontando quello con lo script che ho scritto per quella risposta, ed eseguendo gli stessi dati,

  • La risposta di @nils produce 605 righe (apparentemente perché include modifiche alla directory ),
  • "diff -q -r" produce 352 righe dopo aver eseguito per alcuni minuti e
  • il mio script mostra 252 righe ( i file effettivi sono stati modificati, aggiunti o eliminati)

Per rendere diffcorrettamente conto dei nuovi file, è necessaria anche l' -Nopzione (che non vedo in nessuna delle risposte suggerite). Tuttavia, poiché è molto più lento (ordini di grandezza) rispetto a rsync, migliorare la produzione di quest'ultimo sembra la strada da percorrere.

Ulteriori letture


0

Sono sempre stato parziale a sha1sum (o anche a md5sum; in questo contesto è abbastanza sicuro).

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"

A volte - come se hai troppi file rinominati o spostati - l'ordinamento sul primo campo e quindi fare il diff potrebbe aiutare, ma il più delle volte è abbastanza buono.

Si noti che, rispetto ad alcuni degli altri metodi, questo ha il vantaggio che non è necessario conservare una copia dei file "prima"; solo il file di output md5sum.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.