rsync: फ़ोल्डर्स को सिंक करें, लेकिन अतिरिक्त फ़ाइलों को लक्ष्य में रखें


10

मैं शुरू कर रहा हूं rsyncऔर स्थानीय सिस्टम पर दो फ़ोल्डरों को सिंक करने के लिए इसका उपयोग करने की कोशिश कर रहा हूं । मेरे पास एक स्रोत फ़ोल्डर है, जिसकी सामग्री समय के साथ बदलती है (कुछ फाइलें जोड़ी जाती हैं, कुछ परिवर्तन और कुछ नष्ट हो जाती हैं) और एक लक्ष्य फ़ोल्डर जिसे मैं लगभग स्रोत का दर्पण बनना चाहता हूं। तो जो मैंने कोशिश की वो इस तरह rsync का उपयोग कर रहा था:

rsync -a --delete "${source_dir}" "${target_dir}";

यह लक्ष्य की सामग्री को स्रोत की सामग्री के समान सटीक रखता है। हालाँकि, मैं कुछ फ़ाइलों को लक्षित करने और स्रोत के लिए नहीं जोड़ने में सक्षम होना चाहूंगा, लेकिन मैं नहीं चाहता कि उन्हें हर बार हटा दिया जाए जो मैं rsync करता हूं। दूसरी ओर, जो फाइलें सिंक हो जाती थीं और फिर स्रोत में डिलीट हो जाती थीं, उन्हें अब भी हटा दिया जाना चाहिए।

क्या हर फ़ाइल के लिए कमांड को बदलने के बिना ऐसा करने का एक तरीका है जिसे मैं बाहर करना चाहता हूं?

अद्यतन : मुझे उल्लेख करना चाहिए कि मैं rsync तक सीमित नहीं हूं। यदि किसी अन्य कार्यक्रम में काम हो जाता है, तो वह भी ठीक है। मैं बस rsync का उपयोग करके इसे हल करने की कोशिश की।


हाय @AszunesHeart, बस जिज्ञासु, लेकिन क्या आपने उत्तर का परीक्षण किया?
याकूब Vlijm

क्या आपने --delete विकल्प निकालने की कोशिश की है? यह एक रोबोकॉपी में / MIR विकल्प की तरह है।
एसडीसोलर

जवाबों:


8

rsyncएक विकल्प नामक --exclude-fromविकल्प है जो आपको किसी भी फाइल की सूची वाली एक फाइल बनाने की अनुमति देता है जिसे आप बाहर करना चाहते हैं। जब भी आप एक नया बहिष्करण जोड़ना चाहते हैं, या एक पुराने को हटा सकते हैं, तो आप इस फ़ाइल को अपडेट कर सकते हैं।

यदि आप /home/user/rsync_excludeनए कमांड पर बहिष्कृत फ़ाइल बनाते हैं:

rsync -a --delete --exclude-from="/home/user/rsync_exclude" "${source_dir}" "${target_dir}"

अपवर्जित सूची फ़ाइल बनाते समय, आपको प्रत्येक बहिष्करण नियम को एक अलग पंक्ति में रखना चाहिए। बहिष्करण आपके स्रोत निर्देशिका के सापेक्ष हैं। यदि आपकी /home/user/rsync_excludeफ़ाइल में निम्नलिखित विकल्प हैं:

secret_file
first_dir/subdir/*
second_dir/common_name.*
  • secret_fileआपके स्रोत निर्देशिका में बुलाई गई कोई भी फ़ाइल या निर्देशिका बाहर रखी जाएगी।
  • किसी भी फाइल को ${source_dir}/first_dir/subdirबाहर रखा जाएगा, लेकिन subdirवसीयत का एक खाली संस्करण सिंक किया जाएगा।
  • ${source_dir}/second_dirउपसर्ग के साथ किसी भी फाइल को common_name.नजरअंदाज कर दिया जाएगा। तो common_name.txt, common_name.jpgआदि।

1
मुझे यकीन नहीं है कि यह वही करता है जो मैं चाहता था। इसके अलावा, मुझे हर फ़ाइल या फ़ोल्डर को लक्षित करने के लिए जोड़ा जाना अव्यवहारिक लगता है। मैं ऐसा करने के लिए एक स्वचालित तरीका रखना चाहता हूं। मान लीजिए कि मेरे पास लक्ष्य में विभिन्न स्क्रिप्ट्स हैं जो कई लॉग-फाइल (लक्ष्य में भी) का उत्पादन करती हैं और मैं उन फ़ाइलों के प्रत्येक स्थान को rsync_exclude-file में सूचीबद्ध नहीं करना चाहता। क्या rsync को "याद रखना" बनाने का एक तरीका है कि कौन सी फाइलें जहां सिंक की गई हैं और केवल --delete से प्रभावित होती हैं?
jkrzefski

क्षमा करें, मैंने आपके प्रश्न को गलत बताया, हालांकि मैं आपको स्रोत में जोड़ना चाहता था, और उन लोगों के पास लक्ष्य करने के लिए अपडेट नहीं है। मुझे लगता है कि आप जो चाहते हैं, उसे करने का एक तरीका है, लेकिन मुझे इसे थोड़ा सा करना होगा। मैं एक बार टिप्पणी करूंगा कि मेरे पास संपादन करने का समय है।
एरोनिकल

@jkrzefski यदि आप लक्ष्य में किसी अन्य स्क्रिप्ट से फ़ाइलों का निर्माण कर रहे हैं, और उन्हें स्रोत से बाहर करना चाहते हैं, तो उन लॉग फ़ाइलों के गंतव्य को किसी अन्य फ़ोल्डर में बदलने के लिए क्यों नहीं? संभवतः, यदि आप उन्हें सिंक्रनाइज़ नहीं कर रहे हैं, तो इसलिए कि वे कम महत्वपूर्ण हैं।

6

चूंकि आपने उल्लेख किया है: मैं rsync तक सीमित नहीं हूं:

दर्पण को बनाए रखने के लिए स्क्रिप्ट, लक्ष्य के लिए अतिरिक्त फ़ाइलों को जोड़ने की अनुमति

एक स्क्रिप्ट के नीचे जो आप वर्णन करते हैं वही करता है।

स्क्रिप्ट को वर्बोज़ मोड (स्क्रिप्ट में सेट होने के लिए) में चलाया जा सकता है , जो बैकअप (मिररिंग) की प्रगति को आउटपुट करेगा। यह कहने की आवश्यकता नहीं है कि इसका उपयोग बैकअप लॉग इन करने के लिए भी किया जा सकता है:

क्रिया विकल्प

यहाँ छवि विवरण दर्ज करें


संकल्पना

1. पहले बैकअप पर, स्क्रिप्ट:

  • एक फ़ाइल (लक्ष्य निर्देशिका में) बनाता है, जहां सभी फाइलें और निर्देशिकाएं सूचीबद्ध हैं; .recentfiles
  • लक्ष्य निर्देशिका में सभी फ़ाइलों और निर्देशिकाओं की एक सटीक प्रतिलिपि (दर्पण) बनाता है

2. बैकअप पर अगले और इतने पर

  • स्क्रिप्ट फाइलों की निर्देशिका संरचना और संशोधन की तारीख की तुलना करती है। स्रोत में नई फाइलें और डायरियां दर्पण में कॉपी की जाती हैं। एक ही समय में एक दूसरी (अस्थायी) फ़ाइल बनाई जाती है, वर्तमान फ़ाइलों को सूचीबद्ध करती है और स्रोत निर्देशिका में dirs; .currentfiles
  • इसके बाद, .recentfiles(पिछले बैकअप पर स्थिति को सूचीबद्ध करते हुए) की तुलना की जाती है .currentfilesकेवल वे फ़ाइलें .recentfilesजिनमें .currentfilesसे स्रोत स्पष्ट रूप से हटाए नहीं गए हैं, और उन्हें लक्ष्य से हटा दिया जाएगा।
  • आपके द्वारा लक्ष्य फ़ोल्डर में मैन्युअल रूप से जोड़ी गई फाइलें वैसे भी स्क्रिप्ट द्वारा "देखी गई" नहीं होती हैं, और अकेले रह जाती हैं।
  • अंत में, अगले बैकअप चक्र इत्यादि की सेवा के लिए अस्थायी .currentfilesनाम बदल दिया जाता .recentfilesहै।

लिपी

#!/usr/bin/env python3
import os
import sys
import shutil

dr1 = sys.argv[1]; dr2 = sys.argv[2]

# --- choose verbose (or not)
verbose = True
# ---

recentfiles = os.path.join(dr2, ".recentfiles")
currentfiles = os.path.join(dr2, ".currentfiles")

if verbose:
    print("Counting items in source...")
    file_count = sum([len(files)+len(d) for r, d, files in os.walk(dr1)])
    print(file_count, "items in source")
    print("Reading directory & file structure...")
    done = 0; chunk = int(file_count/5); full = chunk*5

def show_percentage(done):
    if done % chunk == 0:
        print(str(int(done/full*100))+"%...", end = " ")

for root, dirs, files in os.walk(dr1):
    for dr in dirs:
        if verbose:
            if done == 0:
                print("Updating mirror...")
            done = done + 1
            show_percentage(done) 
        target = os.path.join(root, dr).replace(dr1, dr2)
        source = os.path.join(root, dr)
        open(currentfiles, "a+").write(target+"\n")
        if not os.path.exists(target):
            shutil.copytree(source, target)
    for f in files:
        if verbose:
            done = done + 1
            show_percentage(done)
        target = os.path.join(root, f).replace(dr1, dr2)
        source = os.path.join(root, f)
        open(currentfiles, "a+").write(target+"\n") 
        sourcedit = os.path.getmtime(source)
        try:
            if os.path.getmtime(source) > os.path.getmtime(target):
                shutil.copy(source, target)   
        except FileNotFoundError:
            shutil.copy(source, target)

if verbose:
    print("\nChecking for deleted files in source...")

if os.path.exists(recentfiles):
    recent = [f.strip() for f in open(recentfiles).readlines()]
    current = [f.strip() for f in open(currentfiles).readlines()]
    remove = set([f for f in recent if not f in current])
    for f in remove:
        try:
            os.remove(f)
        except IsADirectoryError:
            shutil.rmtree(f)
        except FileNotFoundError:     
            pass
        if verbose:
            print("Removed:", f.split("/")[-1])

if verbose:
    print("Done.")

shutil.move(currentfiles, recentfiles)

कैसे इस्तेमाल करे

  1. स्क्रिप्ट को एक खाली फ़ाइल में कॉपी करें, इसे इस रूप में सहेजें backup_special.py
  2. परिवर्तन -आप चाहते हैं- स्क्रिप्ट के सिर में क्रिया विकल्प:

    # --- choose verbose (or not)
    verbose = True
    # ---
    
  3. तर्क के रूप में इसे स्रोत और लक्ष्य के साथ चलाएं:

     python3 /path/to/backup_special.py <source_directory> <target_directory>
    

गति

मैंने अपने नेटवर्क ड्राइव (NAS) पर कुछ 40.000 फाइलों और डायरियों के साथ 10 जीबी निर्देशिका पर स्क्रिप्ट का परीक्षण किया, इसने बैकअप को rsync के समान समय में बनाया।

पूरी निर्देशिका को अपडेट करने में rsync की तुलना में केवल कुछ सेकंड अधिक, 40.000 फाइलों पर लिया गया, जो कि इमो स्वीकार्य है और कोई आश्चर्य की बात नहीं है, क्योंकि स्क्रिप्ट को अंतिम बने बैकअप के लिए सामग्री की तुलना करने की आवश्यकता है।


हाय @ Aszune'sHeart ने एक स्क्रिप्टेड विकल्प जोड़ा। कृपया उल्लेख करें कि क्या सब स्पष्ट है।
जैकब व्लिजम
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.