डुप्लीकेट फाइलें ढूंढना और उन्हें सिम्बलिंक्स से बदलना


16

मैं डुप्लिकेट फ़ाइलों (यहां तक ​​कि अलग-अलग नामों के साथ) के लिए दिए गए निर्देशिका के अंदर की जांच करने का एक तरीका खोजने की कोशिश कर रहा हूं और उन्हें पहली घटना की ओर इशारा करते हुए सहानुभूति के साथ बदल रहा हूं। मैंने कोशिश की है, fdupesलेकिन यह सिर्फ उन डुप्लिकेट को सूचीबद्ध करता है।
यह संदर्भ है: मैं अपनी पसंद के अनुसार एक आइकन विषय को अनुकूलित कर रहा हूं, और मैंने पाया है कि कई आइकन, भले ही उनके अलग-अलग नाम और उनके मूल फ़ोल्डर के अंदर अलग-अलग स्थान हों, और विभिन्न प्रयोजनों के लिए उपयोग किए जाते हैं, मूल रूप से सिर्फ एक ही हैं चित्र। चूँकि एक ही संशोधन को बीस या तीस बार लागू करना निरर्थक है जब सिर्फ एक वास्तव में आवश्यक है, मैं केवल एक छवि रखना चाहता हूं और अन्य सभी को सहानुभूति देना चाहता हूं।

एक उदाहरण के रूप में, यदि मैं fdupes -r ./निर्देशिका के अंदर भागता हूं, तो testdirयह मेरे लिए निम्न परिणाम दे सकता है:

./file1.png
./file2.png
./subdir1/anotherfile.png
./subdir1/subdir2/yetanotherfile.png

इस आउटपुट को देखते हुए, मैं केवल फ़ाइल रखना चाहूँगा file1.png, सभी अन्य को हटा दूंगा और सभी मूल फ़ाइल नामों को बनाए रखते हुए सिम्लिंक्स के साथ उनकी जगह ले लूंगा। इसलिए file2.pngअपना नाम बरकरार रखेगा, लेकिन file1.pngडुप्लिकेट होने के बजाय एक लिंक बन जाएगा ।

उन लिंक को एक निरपेक्ष पथ की ओर इशारा नहीं करना चाहिए, लेकिन मूल testdirनिर्देशिका के सापेक्ष होना चाहिए ; यानी yetanotherfile.pngकी ओर इशारा किया जाएगा ../../file1.png, को नहीं/home/testuser/.icons/testdir/file1.png

मुझे उन दोनों समाधानों में दिलचस्पी है, जिनमें GUI और CLI शामिल हैं। यह उपयोग करने के लिए अनिवार्य नहीं है fdupesमैंने इसे उद्धृत किया है क्योंकि यह एक ऐसा उपकरण है जिसे मैं जानता हूं, लेकिन मैं उन समाधानों के लिए खुला हूं जो अन्य उपकरणों का भी उपयोग करते हैं।

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

जवाबों:


3

प्रथम; क्या कोई कारण है जो आपको सिमिलिंक का उपयोग करने की आवश्यकता है और सामान्य हार्डलिंक नहीं? मुझे रिश्तेदार पथ के साथ सहानुभूति की आवश्यकता को समझने में कठिन समय हो रहा है। यहां बताया गया है कि मैं इस समस्या को कैसे हल करूंगा:

मुझे लगता है कि fdupes का डेबियन (उबंटू) संस्करण -Lविकल्प का उपयोग करके हार्ड लिंक के साथ डुप्लिकेट को बदल सकता है, लेकिन मेरे पास इसे सत्यापित करने के लिए डेबियन इंस्टॉलेशन नहीं है।

यदि आपके पास -Lविकल्प के साथ कोई संस्करण नहीं है, तो आप कमांडलाइनफू पर मिली इस छोटी सी बैश स्क्रिप्ट का उपयोग कर सकते हैं ।
ध्यान दें कि यह सिंटैक्स केवल बैश में काम करेगा।

fdupes -r -1 path | while read line; do master=""; for file in ${line[*]}; do if [ "x${master}" == "x" ]; then master=$file; else ln -f "${master}" "${file}"; fi; done; done

उपरोक्त कमांड "पथ" में सभी डुप्लिकेट फ़ाइलों को ढूंढेगा और उन्हें हार्डलिंक से बदल देगा। आप ls -ilRइनकोड नंबर को चलाकर और देख कर इसे सत्यापित कर सकते हैं । यहाँ दस समान फ़ाइलों के साथ एक नमूना है:

$ ls -ilR

total 20
3094308 -rw------- 1 username group  5 Sep 14 17:21 file
3094311 -rw------- 1 username group  5 Sep 14 17:21 file2
3094312 -rw------- 1 username group  5 Sep 14 17:21 file3
3094313 -rw------- 1 username group  5 Sep 14 17:21 file4
3094314 -rw------- 1 username group  5 Sep 14 17:21 file5
3094315 drwx------ 1 username group 48 Sep 14 17:22 subdirectory

./subdirectory:
total 20
3094316 -rw------- 1 username group 5 Sep 14 17:22 file
3094332 -rw------- 1 username group 5 Sep 14 17:22 file2
3094345 -rw------- 1 username group 5 Sep 14 17:22 file3
3094346 -rw------- 1 username group 5 Sep 14 17:22 file4
3094347 -rw------- 1 username group 5 Sep 14 17:22 file5

सभी फाइलों में अलग-अलग इनकोड नंबर होते हैं, जिससे वे अलग-अलग फाइल बनाते हैं। अब उन्हें कटौती करने देता है:

$ fdupes -r -1 . | while read line; do j="0"; for file in ${line[*]}; do if [ "$j" == "0" ]; then j="1"; else ln -f ${line// .*/} $file; fi; done; done
$ ls -ilR
.:
total 20
3094308 -rw------- 10 username group  5 Sep 14 17:21 file
3094308 -rw------- 10 username group  5 Sep 14 17:21 file2
3094308 -rw------- 10 username group  5 Sep 14 17:21 file3
3094308 -rw------- 10 username group  5 Sep 14 17:21 file4
3094308 -rw------- 10 username group  5 Sep 14 17:21 file5
3094315 drwx------  1 username group 48 Sep 14 17:24 subdirectory

./subdirectory:
total 20
3094308 -rw------- 10 username group 5 Sep 14 17:21 file
3094308 -rw------- 10 username group 5 Sep 14 17:21 file2
3094308 -rw------- 10 username group 5 Sep 14 17:21 file3
3094308 -rw------- 10 username group 5 Sep 14 17:21 file4
3094308 -rw------- 10 username group 5 Sep 14 17:21 file5

अब सभी फ़ाइलों में एक ही इनकोड संख्या होती है, जिसका अर्थ है कि वे सभी डिस्क पर समान भौतिक डेटा को इंगित करती हैं।

मुझे आशा है कि यह आपकी समस्या को हल करेगा या कम से कम आपको सही दिशा में इंगित करेगा!


मैं याद किया fdupes लिंक, @arnefm साथ ड्यूप्स को बदलने के लिए एक विकल्प होने, लेकिन मैं कुछ भी नहीं देख सकते हैं आदमी है और न ही उस में एक विकल्प है v1.51(Ubuntu 14.04.2 LTS)।
एलेस्टेयर

मेरे कांटे jdupesपर github.com/jbruchon/jdupes में -Lविकल्प है जो डुप्लिकेट सेट की वांछित हार्ड लिंकिंग करता है।
जॉडी ली ब्रूचॉन

मैंने यहां सिर्फ स्क्रिप्ट को ट्विक किया है। यह अभी भी रिक्त स्थान को नहीं संभालेगा, लेकिन अन्य विशेष वर्णों को संभालेगा (मेरे पास फ़ाइलों में URL क्वेरी स्ट्रिंग थी)। इसके अलावा, ${line//…/}भाग मेरे लिए काम नहीं कर रहा था, इसलिए मैंने हार्डलिंक के लिए पहली "मास्टर" फ़ाइल प्राप्त करने के लिए एक क्लीनर तरीका किया।
IBBoard

1
यदि हम rsyncएक अलग प्रकार की फ़ाइल प्रणाली का उपयोग कर रहे हैं, तो क्या हमें सापेक्ष सॉफ्टलिंक की आवश्यकता होगी ? या अगर फ़ाइल सिस्टम पदानुक्रम को संरक्षित नहीं करता है, जैसे कि यह एक बैकअप सर्वर है जो सब कुछ नीचे रखता है /«machine-name»/...? या यदि आप बैकअप से पुनर्स्थापित करना चाहते हैं? मैं यह नहीं देख सकता कि हार्डलिंक को यहां कैसे संरक्षित किया जाएगा। रिश्तेदार सॉफ्टलिंक जीवित रहने का एक बेहतर मौका होगा, मुझे लगता है कि हो सकता है।
बडी

सॉफ्टलिंक्स एक आवश्यकता हो सकती है अगर यह रेपो में रखते समय एक गिट रेपो के भीतर फ़ाइलों को डी-डुप्लिकेट करने के लिए है।
ब्लाकबैट

6

यदि आप ज्यादा स्क्रिप्टिंग नहीं करते हैं तो मैं rdfind की सिफारिश कर सकता हूं । जो डुप्लिकेट फ़ाइलों के लिए दी गई निर्देशिकाओं को स्कैन करेगा और उन्हें हार्ड-या सॉफ्ट-लिंक एक साथ करेगा। मैंने इसे बड़ी सफलता के साथ अपनी रूबी रत्नों की निर्देशिका के लिए उपयोग किया है। यह डेबियन / उबंटू में उपलब्ध है।


4

मेरे पास भी ऐसी ही स्थिति थी, लेकिन मेरे मामले में प्रतीकात्मक लिंक एक सापेक्ष पथ की ओर इशारा करना चाहिए, इसलिए मैंने इस पायथन स्क्रिप्ट को चाल करने के लिए लिखा :

#!/usr/bin/env python
# Reads fdupes(-r -1) output and create relative symbolic links for each duplicate
# usage: fdupes -r1 . | ./lndupes.py

import os
from os.path import dirname, relpath, basename, join
import sys

lines = sys.stdin.readlines()

for line in lines:
    files = line.strip().split(' ')
    first = files[0]
    print "First: %s "% first
    for dup in files[1:]:
        rel = os.path.relpath(dirname(first), dirname(dup))
        print "Linking duplicate: %s to %s" % (dup, join(rel,basename(first)))
        os.unlink(dup)
        os.symlink(join(rel,basename(first)), dup)

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


1

तो, arnefm द्वारा दिया गया उत्तर (जो कि पूरे इंटरनेट पर कॉपी किया गया है) फ़ाइल नामों में रिक्त स्थान के साथ सौदा नहीं करता है। मैंने एक स्क्रिप्ट लिखी है जो फाइलों में रिक्त स्थान से संबंधित है।

#!/bin/bash
fdupes -r -1 CHANGE_THIS_PATH | sed -e 's/\(\w\) /\1|/g' -e 's/|$//' > files
while read line; do
        IFS='|' read -a arr <<< "$line"
        orig=${arr[0]}
        for ((i = 1; i < ${#arr[@]}; i++)); do
                file="${arr[$i]}"
                ln -sf "$orig" "$file"
        done 
done < files

यह क्या करता है, यह पता लगाया जाता है कि उन्हें डुप्लिकेट लिखा गया है और उन्हें 'फाइल' नाम की फाइल में अलग कर दिया गया है।

फिर यह फ़ाइल को पीछे, लाइन द्वारा लाइन में, एक सरणी में पढ़ता है, और सरणी के प्रत्येक तत्व को PIPE द्वारा सीमांकित किया जाता है।

यह तब सरणी के सभी गैर-पहले तत्वों पर पुनरावृत्ति करता है, फ़ाइल को पहले तत्व के सिम्लिंक के साथ बदल देता है।

बाहरी फ़ाइल ('फाइलें') को हटाया जा सकता है, अगर fdupes कमांड को सब-उप में निष्पादित किया जाता है, तो इसे सीधे ही पढ़ा जाता है, लेकिन यह तरीका स्पष्ट लगता है।


2
क्या यह संस्करण पाइप वाले नामों वाली फाइलों से निपटता है? मुझे लगता है कि न तो संस्करण नई नामों वाली फ़ाइल नामों को संभालता है, लेकिन यह कुछ और के बजाय fdupes की सीमा है।
डेग

यह नहीं है, लेकिन आप IFS को अपनी इच्छानुसार सेट कर सकते हैं (सेड रिप्लेसमेंट में मूल्य भी संशोधित कर सकते हैं), तो आपको कोई समस्या नहीं होनी चाहिए (IFS to 'ñ' या ऐसा कुछ काम करना चाहिए)
डेविड वेंचुरा

यह टूटी हुई सीलिंक बनाता है, और मेरे पास खुद से जुड़ी फाइलें हैं। का उपयोग न करें
MrMesees

0

कुछ खटिया सामने:

  • BASH विशिष्ट
  • फ़ाइल नामों में कोई स्थान नहीं है
  • मान लें कि प्रत्येक पंक्ति में अधिकतम 2 फ़ाइलें हैं।

fdupes -1r common/base/dir | while read -r -a line ; do ln -sf $(realpath --relative-to ${line[1]} ${line[0]}) ${line[1]}; done

अगर 2 से अधिक फाइलें डुप्लिकेट हैं (जैसे कि file1 file2 file3) तो हमें प्रत्येक जोड़ी के लिए एक सिमलिंक बनाने की आवश्यकता है - file1, file2 और file1, file3 को 2 अलग-अलग मामलों के रूप में देखें:

if [[ ${#line[@]} -gt 2 ]] ;then 
  ln -sf $(realpath --relative-to ${line[1]} ${line[0]}) ${line[1]} 
  ln -sf $(realpath --relative-to ${line[2]} ${line[0]}) ${line[2]} 
  ...
fi

स्वचालित रूप से प्रति पंक्ति डुप्लिकेट की एक मनमानी संख्या को संभालने के लिए इसे खर्च करने से थोड़ा अधिक प्रयास होगा।

एक अन्य तरीका यह होगा कि पहले निरपेक्ष रास्तों पर सहानुभूति बनाएं, फिर उन्हें परिवर्तित करें:

fdupes -1r /absolute/path/common/base/dir | while read -r -a line ; do ln -sf ${line[0]} ${line[1]}; done
chroot /absolute/path/common/base/dir ; symlinks -cr .

यह @Gilles: /unix//a/100955/77319 द्वारा उत्तर पर आधारित है

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.