linux diff інструменти: створити список модифікованих файлів


14

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

оновлення: diff -qrне дає дуже сприятливих результатів. Вихід diff -qrтакож повинен бути оброблений. Чи є кращий спосіб?


який приклад "зручного" виводу?
frogstarr78

Відповіді:


8

Для цього у мене простий підхід: використовуйте режим перегляду rsync:

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).
Стів Келет

Так, також пакунок пакунків для 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 , сортування та 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 -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" "вивести оновлення, використовуючи вказаний FORMAT", який тут "% 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

Примітка. Сценарій не перевіряється, тому вищенаведений приклад "псевдокод натхненний"


Давайте займемося ще одним, але з git

Створіть кілька прикладних файлів, з якими можна грати

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 dir та імпортуйте новий dir

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"

Іноді - наприклад, якщо у вас занадто багато файлів перейменовано або переміщено - сортування за першим полем, а потім виконання розрізнень може допомогти, але більшість часу це досить добре.

Зауважте, що порівняно з деякими іншими методами це перевага, що вам не потрібно зберігати копію файлів "до"; тільки вихідний файл md5sum.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.