linux diff tools: создать список измененных файлов


14

Как создать список измененных файлов программно с помощью инструментов командной строки linux? Меня не интересует разница в каком-либо конкретном файле (дельта, патч). Я просто хочу получить список новых или измененных файлов по сравнению с предыдущим выпуском продукта. Так что я могу опубликовать новое обновление продукта.

обновление: diff -qrне дает очень удобного вывода. Вывод diff -qrтакже должен быть обработан. Есть ли лучший способ?


каков пример "удобного" вывода?
frogstarr78

Ответы:


8

У меня есть простой подход к этому: используйте режим rsync-preview:

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

Файлы, которые отображаются как «подлежащие удалению» этой командой, будут «новыми» файлами. Другие, которые должны быть переданы, изменились каким-то образом. Смотрите rsync-man-страницу для более подробной информации.


13

Вы можете использовать diff toool: смотрите параметры -q и -r

-q  --brief
Output only whether files differ.

-r  --recursive
Recursively compare any subdirectories found.

Пример:

diff -qr dir1 dir2

Абсолютно ужасный и нечитаемый вывод, загроможденный бессмысленной информацией, Only inкоторая появляется, даже если каталоги являются идеальными копиями. Мне нужно было сравнить изменения со старой ревизией и в итоге загрузить целую ревизию в отдельный каталог и использовать стандартные инструменты SVN для сравнения. Это, кажется, единственный путь ...
Привет-Ангел

3

В diffutilsкомплект входит lsdiffинструмент. Просто передайте вывод команды diff -ulsdiff:

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

Хорошее предложение, спасибо. Был в patchutilsупаковке для меня (CentOS 5.x).
Стив Келет

Да, пакет patchutils для Ubuntu / Debian тоже.
artfulrobot

1

Я бы просто прикоснулся к файлу во время каждого обновления, а затем вы можете найти файлы, которые были изменены с тех пор с find /tree/location -newer /last/update/file -print


1

Чтобы взять только имена файлов, которые они изменили, я использую эту команду:

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

Если вам необходимо исключить некоторые файлы в виде объектных файлов или библиотечных файлов, вы можете использовать:

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

1

Чтобы создать список новых или измененных файлов программно, лучшее решение, которое я мог бы предложить, это использовать rsync , sort и uniq :

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

Позвольте мне объяснить на этом примере: мы хотим сравнить два выпуска dokuwiki, чтобы увидеть, какие файлы были изменены, а какие были созданы заново.

Мы принести гудроны с Wget и извлечь их в каталогах old/и 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

Запуск rsync в одну сторону может пропустить вновь созданные файлы, как показывает сравнение rsync и diff:

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

дает следующий вывод:

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

Запуск rsync только в одном направлении пропускает вновь созданные файлы, и наоборот, пропустит удаленные файлы, сравните вывод diff:

diff -qr old/ new/

дает следующий вывод:

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

Запуск Rsync оба способов и сортировка вывода для удаления дубликатов показывает , что каталог data/pages/playground/и файл data/pages/playground/playground.txtбыли пропущены первоначально:

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

дает следующий вывод:

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 запускается с этими аргументами:

  • -r "вербоваться в каталоги",
  • -c также сравнивать файлы одинакового размера и только «пропускать по контрольной сумме, а не по времени и размеру»,
  • -n «выполнить пробный запуск без внесения изменений», и
  • --out-format="%n" «выводить обновления, используя указанный ФОРМАТ», который здесь «% n» только для имени файла

Вывод (список файлов) rsyncв обоих направлениях объединяется и сортируется с использованием sort, и этот отсортированный список затем сокращается путем удаления всех дубликатов сuniq



0

Это может сделать трюк:

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

Обычно вы помещаете файлы в какую-то систему контроля версий, такую ​​как SubVersion или git, поскольку они могут сделать это для вас из коробки.

Но вы можете сделать быстрый скрипт с циклом for на dir1, а затем сравнить каждый файл с файлом в dir2. Цикл for может посмотреть на код выхода из diff, чтобы узнать, были ли файлы другими.

Может быть, что-то вроде этого:

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

Примечание. Скрипт не тестировался, поэтому приведенный выше пример - псевдокод в стиле bash ...


Давайте еще раз, но с мерзавцем

Создайте несколько примеров файлов для воспроизведения

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

Затем введите dir и импортируйте dir1

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

Выйдите и измените dir1 (чтобы он стал вашим dir2).

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

Затем перейдите в каталог git и импортируйте новый каталог

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

Теперь спросите git, что изменилось (с помощью команды status)

git status -s

Вывод представляет собой список с изменениями, который выглядит следующим образом:

 M test1/test11/t1.txt

0

Может быть, ты был бы счастлив с чем-то другим. Попробуй git.

Сделайте это в качестве примера:

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

gitбудет отслеживать ваши файлы для вас. Команда git statusпокажет вам все файлы, которые были изменены с момента последнего коммита.


0

Это похоже на rsync: показывать, когда новый файл в месте назначения должен быть перезаписан (спрашивается позже, но не является дубликатом).

Как указано в вопросе, "diff -q -r" может потребовать некоторой обработки, чтобы быть полезным. Вопрос не уточнил форму вывода; ответы дают различные типы отчетов.

rsyncявляется полезным инструментом для этой цели, потому что это гораздо быстрее, чем diff. Однако решение, предложенное @nils, гораздо более многословно (и содержит больше файлов), чем фактические различия между старыми / новыми деревьями каталогов. Например, сравнивая это со сценарием, который я написал для этого ответа, и работая с теми же данными,

  • Ответ @nils выдает 605 строк (очевидно, потому что он включает в себя изменения каталога ),
  • «diff -q -r» выдает 352 строки после запуска в течение нескольких минут, и
  • мой скрипт показывает 252 строки ( реальные файлы изменены, добавлены или удалены)

Чтобы diffправильно учесть новые файлы, вам также понадобится -Nопция (которую я не вижу ни в одном из предложенных ответов). Тем не менее, поскольку он намного медленнее (на несколько порядков), чем rsyncулучшение выпуска последнего, кажется, путь.

дальнейшее чтение


0

Я всегда был неравнодушен к sha1sum (или даже md5sum; в этом контексте это довольно безопасно).

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"

Иногда - например, если вы переименовываете или перемещаете слишком много файлов - сортировка по первому полю, а затем выполнение diff может помочь, но в большинстве случаев этого достаточно.

Обратите внимание, что по сравнению с некоторыми другими методами это дает то преимущество, что вам не нужно хранить копию файлов «before»; только выходной файл md5sum.

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.