เปรียบเทียบไดเรกทอรี แต่ไม่ใช่เนื้อหาของไฟล์


21

ด้วย diff -r ฉันสามารถทำงานนี้ได้อย่างไรก็ตามใช้เวลานานมากเพราะ diff ตรวจสอบเนื้อหาของไฟล์

ฉันต้องการสิ่งที่กำหนดว่าไฟล์สองไฟล์นั้นมีขนาดเท่ากันแก้ไขล่าสุด ฯลฯ แต่ไม่มีการตรวจสอบทีละบิตไฟล์ (ตัวอย่างเช่นวิดีโอใช้เวลานานมาก)

มีวิธีอื่น ๆ ?

คำตอบ:


20

rsync โดยค่าเริ่มต้นจะเปรียบเทียบข้อมูลเมตาของไฟล์เท่านั้น

rsync -n -a -i --delete source/ target/

คำอธิบาย:

  • -n อย่าคัดลอกหรือลบ <- นี่คือสิ่งสำคัญ !! 1
  • -a เปรียบเทียบข้อมูลเมตาทั้งหมดของไฟล์เช่นเวลาประทับและคุณลักษณะ
  • -i พิมพ์ข้อมูลหนึ่งบรรทัดต่อไฟล์
  • --delete ยังรายงานไฟล์ที่ไม่ได้อยู่ในแหล่งที่มา

หมายเหตุ: มันเป็นสิ่งสำคัญที่จะผนวกชื่อไดเรกทอรีด้วยเครื่องหมายทับ นี่คือสิ่งที่ rsync

หากคุณต้องการเห็นบรรทัดที่พิมพ์สำหรับไฟล์ที่เหมือนกันแล้วให้-iสองครั้ง

rsync -n -a -ii --delete source/ target/

เอาท์พุทตัวอย่าง:

*deleting   removedfile   (file in target but not in source)
.d..t...... ./            (directory with different timestamp)
>f.st...... modifiedfile  (file with different size and timestamp)
>f+++++++++ newfile       (file in source but not in target)
.f          samefile      (file that has same metadata. only with -ii)

จำไว้ว่า rsync เปรียบเทียบ metadata เท่านั้น นั่นหมายความว่าหากเนื้อหาไฟล์เปลี่ยนแปลง แต่ข้อมูลเมตายังคงเดิม rsync จะรายงานว่าไฟล์นั้นเหมือนกัน นี่เป็นสถานการณ์ที่ไม่น่าเป็นไปได้ ดังนั้นเชื่อว่าเมื่อเมทาดาทาเหมือนกันข้อมูลก็เหมือนกันหรือคุณต้องเปรียบเทียบข้อมูลไฟล์ทีละบิต

โบนัส: สำหรับข้อมูลความคืบหน้าดูที่นี่: เวลาประมาณการหรืองานเหลือเพื่อสิ้นสุดสำหรับ rsync หรือไม่


1
ทับในsource/และtarget/นอกจากนี้ยังมีทั้งสิ่งที่สำคัญมาก! (โดยพวกเขาคุณจะเปรียบเทียบชื่อแหล่งที่มาและไดเรกทอรีเป้าหมายพร้อมกับชื่อไฟล์เด็กดังนั้นชื่อไฟล์ทั้งหมดจะแตกต่างกัน.)
peschü

ฉันหวังว่าฉันได้อ่านความคิดเห็นของคุณก่อนหน้านี้เป็นสิ่งสำคัญมาก! ฉันตัดเครื่องหมายสแลชในซอร์สเท่านั้นจากนั้นฉันก็สงสัยว่าทำไมไฟล์ในเป้าหมายจึงไม่ปรากฏขึ้น*deletingแต่ไฟล์ซึ่งอยู่ในซอร์สก็แสดงขึ้นมา เครื่องหมายทับนั้นง่ายต่อการลืมโดยไม่ตั้งใจและจากนั้นคุณจะได้ผลลัพธ์ที่น่าเชื่อถือ แต่ผิด
user643011

3

ใช้-q( --brief) ตัวเลือกที่มีdiff -r( diff -qr) จากinfoหน้าสำหรับ GNU diff:

1.6 สรุปไฟล์ที่แตกต่าง

เมื่อคุณต้องการค้นหาว่าไฟล์แตกต่างกันหรือไม่และคุณไม่สนใจความแตกต่างคุณสามารถใช้รูปแบบเอาต์พุตสรุป ในรูปแบบนี้แทนที่จะแสดงความแตกต่างระหว่างไฟล์diff' simply reports whether files differ. Theตัวเลือก --brief '(`-q') เลือกรูปแบบผลลัพธ์นี้

รูปแบบนี้มีประโยชน์อย่างยิ่งเมื่อเปรียบเทียบเนื้อหาของสองไดเรกทอรี นอกจากนี้ยังเร็วกว่าการทำบรรทัดปกติด้วยการเปรียบเทียบบรรทัดเนื่องจาก `diff 'สามารถหยุดการวิเคราะห์ไฟล์ได้ทันทีที่รู้ว่ามีความแตกต่าง

สิ่งนี้จะไม่เปรียบเทียบทีละบรรทัด แต่เป็นไฟล์โดยรวมซึ่งประมวลผลเร็วขึ้นมาก (สิ่งที่คุณกำลังมองหา)


1
ปัญหาของ - q คือมันเปรียบเทียบปกติและเมื่อพบว่าหยุดความแตกต่าง (ถ้าเป็นโหมดปกติมันยังคงเปรียบเทียบ) ดังนั้นหากไฟล์ขนาดใหญ่เหมือนกันมันจะมีอายุมาก
eez0

2

ต่อไปนี้เป็นสคริปต์ python ฉบับย่อที่จะตรวจสอบว่าชื่อไฟล์ mtimes และขนาดไฟล์เหมือนกันทั้งหมด:

import os
import sys

def getStats(path):
    for pathname, dirnames, filenames in os.walk(path):
        for filename in ( os.path.join(pathname, x) for x in filenames ):
            stat = os.stat(filename)
            yield filename[len(path):], stat.st_mtime, stat.st_size

sys.exit(tuple(getStats(sys.argv[1])) != tuple(getStats(sys.argv[2])))

1

หากคุณจำเป็นต้องรู้ว่าไฟล์จากสองระบบไฟล์แตกต่างกัน (โดยไม่ต้องดูไฟล์ภายใน) คุณสามารถทำสิ่งนี้:

find /opt/branch1 -type f | sort | xargs -i md5sum {} >/tmp/branch1;
find /opt/branch2 -type f | sort | xargs -i md5sum {} >/tmp/branch2;
diff /tmp/branch1 /tmp/branch2;

HTH


0

ตามสคริปต์ของ Chris Down สคริปต์นี้เป็น "ภาพ" มากกว่าเล็กน้อย เรียกว่ามีสองข้อโต้แย้งfolder1และfolder2มันจะเดินไปที่โฟลเดอร์แรกและสำหรับแต่ละไฟล์ค้นหาไฟล์ที่เกี่ยวข้องในโฟลเดอร์ที่สอง หากพบพา ธ สัมพัทธ์จะถูกพิมพ์เป็นสีเขียวหากมีเวลาหรือขนาดแตกต่างกันจะถูกพิมพ์เป็นสีเหลืองและหากไม่พบก็จะพิมพ์เป็นสีแดง

#!/usr/bin/env python

import os
import sys
from termcolor import colored

def compare_filestats(file1,file2):
    """
    Compares modified time and size between two files.
    Return:
        -1 if file1 or file2 does not exist
         0 if they exist and compare equal
         1 if they have different modified time, but same size
         2 if they have different size, but same modified time
         3 if they have different size, and different modified time
    """

    if not os.path.exists(file1) or not os.path.exists(file2):
        return -1

    stat1 = os.stat(file1)
    stat2 = os.stat(file2)

    return (stat1.st_mtime != stat2.st_mtime) \
        + 2*(stat1.st_size != stat2.st_size)

def compare_folders(folder1,folder2):
    """
    folder1: serves as reference and will be walked through
    folder2: serves as target and will be querried for each file in folder1

    Prints colored status for each file in folder1:
        missing: file was not found in folder2 
        mtime  : modified time is different
        size   : filesize is different
        ok     : found with same filestats
    """
    for dirpath, dirnames, filenames in os.walk(folder1):
        for file1 in ( os.path.join(dirpath, x) for x in filenames ):
            relpath = file1[len(folder1):]
            file2 = os.path.join( folder2, relpath )
            comp = compare_filestats(file1,file2)

            if comp < 0:
                status = colored('[missing]','red')
            elif comp == 1:
                status = colored('[mtime  ]','yellow')
            elif comp >= 2:
                status = colored('[size   ]','yellow')
            else:
                status = colored('[ok     ]','green')

            print status, relpath

if __name__ == '__main__':
    compare_folders(sys.argv[1],sys.argv[2])

โปรดทราบว่านี่ไม่เพียงพอที่จะตัดสินใจว่าทั้งสองโฟลเดอร์เหมือนกันคุณจะต้องเรียกใช้ทั้งสองวิธีเพื่อให้แน่ใจ ในทางปฏิบัติหากคุณเพียงต้องการทราบว่าโฟลเดอร์เหมือนกันหรือไม่สคริปต์ของคริสจะดีกว่า หากคุณต้องการทราบว่ามีอะไรหายไปหรือแตกต่างจากโฟลเดอร์หนึ่งไปยังอีกโฟลเดอร์สคริปต์ของฉันจะบอกคุณ

หมายเหตุ: คุณจะต้อง termcolor pip install termcolorติดตั้ง


0

หากคุณต้องการเปรียบเทียบเฉพาะโครงสร้างและข้อมูลพื้นฐานบางอย่างเกี่ยวกับไฟล์คุณสามารถลองดังนี้:

diff <(cd $DIR1 && ls -laR) <(cd $DIR2 && ls -laR)

ฉันไม่ได้ทดสอบดังนั้นจึงยินดีรับการแก้ไข :)


2
สิ่งนี้จะไม่ทำงานเนื่องจากชื่อไดเรกทอรีจะอยู่ในผลลัพธ์ด้วย
Chris Down

จะเป็นอย่างไรถ้าเราจะยกเว้นคอลัมน์แรกที่มีชื่อไดเรกทอรี ชอบ <(ls -laR | awk '{$ 1 = ""; print}')
Volodymyr

บรรทัดทั้งหมดไม่ใช่ชื่อไดเรกทอรีดังนั้นจึงไม่สามารถทำงานได้อย่างถูกต้อง
Chris Down

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