เครื่องมือ diff linux: สร้างรายการไฟล์ที่แก้ไข


14

ฉันจะสร้างรายการไฟล์ที่ถูกแก้ไขโดยใช้เครื่องมือโดยใช้เครื่องมือบรรทัดคำสั่ง linux ได้อย่างไร ฉันไม่สนใจความแตกต่างของไฟล์ใด ๆ (เดลต้าแพทช์) ฉันแค่ต้องการมีรายการไฟล์ใหม่หรือไฟล์ที่ปรับเปลี่ยนแล้วเมื่อเทียบกับรุ่นก่อนหน้า เพื่อให้ฉันสามารถเผยแพร่อัปเดตผลิตภัณฑ์ใหม่

อัปเดต: diff -qrไม่สร้างผลลัพธ์ที่น่าเชื่อถือมาก ผลลัพธ์ของdiff -qrยังจะต้องมีการประมวลผล มีวิธีที่ดีกว่านี้ไหม?


ตัวอย่างของเอาต์พุต "สะดวก" คืออะไร
frogstarr78

คำตอบ:


8

ฉันมีวิธีง่าย ๆ สำหรับสิ่งนี้: ใช้โหมด rsync-preview:

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

ไฟล์ที่แสดงเป็น "จะถูกลบ" โดยคำสั่งนั้นจะเป็นไฟล์ "ใหม่" คนอื่น ๆ ที่จะถ่ายโอนมีการเปลี่ยนแปลงในทางใดทางหนึ่ง ดู rsync-man-page สำหรับรายละเอียดเพิ่มเติม


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 -uไปยัง lsdiff:

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

คำแนะนำที่ดีขอบคุณ อยู่ในpatchutilsแพ็คเกจสำหรับฉัน (CentOS 5.x)
Steve Kehlet

ใช่แพ็คเกจ 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 สองรุ่นเพื่อดูว่าไฟล์ใดบ้างที่ถูกเปลี่ยนแปลงและไฟล์ไหนที่เพิ่งถูกสร้างขึ้นใหม่

เราดึงข้อมูล tars ด้วย 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" เป็น "การอัพเดตเอาต์พุตโดยใช้ 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 for loop บน dir1 จากนั้นเปรียบเทียบทุกไฟล์กับหนึ่งใน dir2 การวนรอบสำหรับสามารถดูรหัสทางออกจากต่างเพื่อทราบว่าไฟล์แตกต่างกัน

อาจจะเป็นสิ่งนี้:

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

หมายเหตุ:สคริปต์ไม่ได้ทดสอบดังนั้นตัวอย่างข้างต้นคือ "bash pseudocode ซึ่งได้แรงบันดาลใจ" ...


เราจะไปอีกครั้ง แต่มีคอมไพล์

สร้างไฟล์ตัวอย่างที่จะเล่นด้วย

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"

บางครั้งเช่นถ้าคุณมีการเปลี่ยนชื่อหรือย้ายไฟล์มากเกินไป - การเรียงลำดับในฟิลด์แรกจากนั้นการทำ diff จะช่วยได้ แต่ส่วนใหญ่เวลานี้ดีพอ

โปรดทราบว่าเมื่อเปรียบเทียบกับวิธีอื่น ๆ บางวิธีสิ่งนี้มีข้อดีที่คุณไม่จำเป็นต้องเก็บสำเนาของไฟล์ "ก่อน" เฉพาะไฟล์เอาต์พุต md5sum

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.