फाइल्स का उपयोग करते हुए निर्देशिका संरचना को संरक्षित करें


22

मैंने निम्नलिखित स्क्रिप्ट बनाई है जो पुराने दिनों की फ़ाइलों को स्रोत निर्देशिका से गंतव्य निर्देशिका तक परिभाषित करती है। यह पूरी तरह से काम कर रहा है।

#!/bin/bash

echo "Enter Your Source Directory"
read soure

echo "Enter Your Destination Directory"
read destination 

echo "Enter Days"
read days



 find "$soure" -type f -mtime "-$days" -exec mv {} "$destination" \;

  echo "Files which were $days Days old moved from $soure to $destination"

यह स्क्रिप्ट फ़ाइलों को महान बनाती है, यह स्रोत उपनिर्देशिका की फ़ाइलें भी ले जाती है, लेकिन यह गंतव्य निर्देशिका में उपनिर्देशिका नहीं बनाती है। मैं इसमें यह अतिरिक्त सुविधा लागू करना चाहता हूं।

उदाहरण के साथ

/home/ketan     : source directory

/home/ketan/hex : source subdirectory

/home/maxi      : destination directory

जब मैं इस स्क्रिप्ट को चलाता हूं, तो यह भी हैक्सी की फाइलों को मैक्सी डायरेक्टरी में ले जाती है, लेकिन मुझे जरूरत है कि उसी हेक्स को मैक्सी डायरेक्टरी में बनाया जाए और उसकी फाइल्स को वहीं हेक्स में मूव करें।

जवाबों:


13

दौड़ने के बजाय mv /home/ketan/hex/foo /home/maxi, आपको उत्पादित पथ के आधार पर लक्ष्य निर्देशिका को अलग-अलग करना होगा find। यह आसान है यदि आप पहले स्रोत निर्देशिका में बदलते हैं और चलाते हैं find .। अब आप अपने द्वारा उत्पादित प्रत्येक आइटम के लिए गंतव्य निर्देशिका को प्रस्तुत कर सकते हैं find। यदि आप find … -execआवश्यक हों तो लक्ष्य निर्धारण करने के लिए, और यदि आवश्यक हो तो लक्ष्य निर्देशिका बनाने के लिए आपको कमांड में एक शेल चलाना होगा ।

destination=$(cd -- "$destination" && pwd) # make it an absolute path
cd -- "$source" &&
find . -type f -mtime "-$days" -exec sh -c '
  mkdir -p "$0/${1%/*}"
  mv "$1" "$0/$1"
' "$destination" {} \;

ध्यान दें कि यदि $destinationविशेष वर्ण हैं, तो मुद्दों को उद्धृत करने से बचने के लिए , आप इसे शेल स्क्रिप्ट के अंदर प्रतिस्थापित नहीं कर सकते। आप इसे पर्यावरण को निर्यात कर सकते हैं ताकि यह आंतरिक शेल तक पहुंच जाए, या आप इसे एक तर्क के रूप में पारित कर सकते हैं (यही मैंने किया था)। आप shकॉल को समूहीकृत करके निष्पादन के समय को बचा सकते हैं:

destination=$(cd -- "$destination" && pwd) # make it an absolute path
cd -- "$source" &&
find . -type f -mtime "-$days" -exec sh -c '
  for x do
    mkdir -p "$0/${x%/*}"
    mv "$x" "$0/$x"
  done
' "$destination" {} +

वैकल्पिक रूप से, zsh में, आप zmvफ़ंक्शन का उपयोग कर सकते हैं , .और m ग्लोब क्वालिफायर केवल सही तिथि सीमा में नियमित फ़ाइलों से मेल खाते हैं। mvयदि आवश्यक हो तो आपको एक वैकल्पिक फ़ंक्शन पास करना होगा जो पहले लक्ष्य निर्देशिका बनाता है।

autoload -U zmv
mkdir_mv () {
  mkdir -p -- $3:h
  mv -- $2 $3
}
zmv -Qw -p mkdir_mv $source/'**/*(.m-'$days')' '$destination/$1$2'

for x do, आपको एक याद आ ;रही है :)। इसके अलावा, मुझे नहीं पता कि आप क्या हासिल करना चाहते थे $0लेकिन मुझे पूरा यकीन है कि यह sh:) होगा ।
1928 में मिशैल गोरनी

@ MichałGórny for x; doतकनीकी रूप से POSIX- अनुरूप ( व्याकरण की जांच ) नहीं है, लेकिन आधुनिक गोले दोनों की अनुमति देते हैं for x doऔर for x; do; कुछ पुराने बॉर्न शेल नहीं डूबे थे for x; do। आधुनिक गोले के साथ, पर sh -c '…' arg0 arg1 arg2 arg3, arg0हो जाता है $0, arg1हो जाता है $1, आदि यदि आप चाहते हैं $0होने के लिए sh, आप लिखने की जरूरत है sh -c '…' sh arg1 arg2 arg3। फिर से, कुछ बॉर्न शेल ने अलग तरह से व्यवहार किया, लेकिन पोसिक्स इसे निर्दिष्ट करता है।
गिल्स एसओ- बुराई को रोकें

pushdयह एक बेहतर विकल्प की तरह लगता है cd, क्योंकि यह वर्तमान वातावरण में कम दखल देता है।
jpmc26

16

मुझे पता findथा कि निर्दिष्ट किया गया था, लेकिन यह एक नौकरी के लिए लगता है rsync

मैं अक्सर निम्नलिखित का उपयोग करता हूं:

rsync -axuv --delete-after --progress Source/ Target/

यदि आप किसी विशेष फ़ाइल-प्रकार ( उदाहरण ) की फ़ाइलों को केवल स्थानांतरित करना चाहते हैं तो यहां एक अच्छा उदाहरण है :

rsync -rv --include '*/' --include '*.js' --exclude '*' --prune-empty-dirs Source/ Target/

दूसरों समाधान की तुलना में :) अधिक स्वच्छ
Guillaume

2
मैंने पाया कि --remove-source-filesसहायक था, जो प्रभावी रूप से नकल के बजाय फ़ाइलों को स्थानांतरित करने का कारण बनता है। यह rsync का एक भयानक उपयोग है।
टॉम

3

आप इसे खोजने के दो उदाहरणों का उपयोग कर सकते हैं (1)

वहाँ हमेशा cpio (1) है

(cd "$soure" && find  | cpio -pdVmu "$destination")

Cpio के तर्कों की जाँच करें। जो मैंने दिया


1
यह व्हॉट्सएप के साथ किसी भी फाइलनाम पर टूट जाएगा।
क्रिस डाउन

1
यह उन्हें स्थानांतरित करने के बजाय फ़ाइलों की प्रतिलिपि बनाता है।
गिल्स एसओ- बुराई को रोकना '

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

3

यह उतना कुशल नहीं है, लेकिन कोड को पढ़ना और समझना आसान है, मेरी राय में, यदि आप बस फाइलों को कॉपी करते हैं और बाद में हटाते हैं।

find /original/file/path/* -mtime +7 -exec cp {} /new/file/path/ \;
find /original/file/path/* -mtime +7 -exec rm -rf {} \;

सूचना: स्वचालित संचालन के लिए @MV द्वारा खोजा गया फ़्लाव:

दो अलग-अलग ऑपरेशन का उपयोग करना जोखिम भरा है। यदि कुछ फाइलें कॉपी ऑपरेशन किए जाने के 7 दिन से अधिक पुरानी हो जाती हैं, तो उन्हें कॉपी नहीं किया जाएगा, लेकिन वे डिलीट ऑपरेशन द्वारा हटा दिए जाएंगे। कुछ के लिए मैन्युअल रूप से एक बार किया जाना एक मुद्दा नहीं हो सकता है, लेकिन स्वचालित स्क्रिप्ट के लिए यह डेटा हानि हो सकती है


2
दो अलग-अलग ऑपरेशन का उपयोग करना जोखिम भरा है। यदि कुछ फाइलें कॉपी ऑपरेशन किए जाने के 7 दिन से अधिक पुरानी हो जाती हैं, तो उन्हें कॉपी नहीं किया जाएगा, लेकिन वे डिलीट ऑपरेशन द्वारा हटा दिए जाएंगे। कुछ के लिए मैन्युअल रूप से एक बार किया जाना एक मुद्दा नहीं हो सकता है, लेकिन स्वचालित स्क्रिप्ट के लिए यह डेटा हानि हो सकती है।
एम.वी.

2
इस दोष का आसान समाधान यह है कि एक बार खोज को चलाएं, सूची को टेक्स्ट फ़ाइल के रूप में सहेजें, और फिर कॉपी करने के लिए दो बार xargs का उपयोग करें और फिर हटाएं।
डेविड एम। पर्लमैन

1

आप findअपने गंतव्य पथ द्वारा लौटाए गए फ़ाइल के पूर्ण पथ को जोड़कर ऐसा कर सकते हैं :

find "$soure" -type f -mtime "-$days" -print0 | xargs -0 -I {} sh -c '
    file="{}"
    destination="'"$destination"'"
    mkdir -p "$destination/${file%/*}"
    mv "$file" "$destination/$file"'

क्रिस अब अपने पूरे घर को मैक्सी में ले जाता है
केतन पटेल

@ K.KPatel नहीं, यह नहीं है। यह केवल आपकी निर्देशिका संरचना को बनाए रखता है।
क्रिस डाउन

यह टूट जाता है यदि $destinationविशेष वर्ण होते हैं, क्योंकि यह आंतरिक खोल में विस्तार से गुजरता है। शायद आपका मतलब था destination='\'"$destination"\''? वह अब भी टूटता है '। इसके अलावा, यह फ़ाइलों को बनाता है जैसे की /home/maxi/home/ketan/hex/fooबजाय /home/maxi/hex/foo
गिल्स एसओ- बुराई को रोकना '

0

बेहतर (सबसे तेज और बिना मूव के बजाय कॉपी करके स्टोरेज स्पेस का उपभोग करना), फ़ाइल-नामों से भी प्रभावित नहीं होता है यदि उनके नाम में विशेष अक्षर होते हैं:

export destination
find "$soure" -type f "-$days" -print0 | xargs -0 -n 10 bash -c '
for file in "$@"; do
  echo -n "Moving $file to $destination/"`dirname "$file"`" ... "
  mkdir -p "$destination"/`dirname "$file"`
  \mv -f "$file" "$destination"/`dirname "$file"`/ || echo " fail !" && echo "done."
done'

या अधिक तेज़, मल्टी-सीपीयू के लिए एक ही समय में "समानांतर" कमांड का उपयोग करके फ़ाइलों का एक गुच्छा ले जाना:

echo "Move oldest $days files from $soure to $destination in parallel (each 10 files by "`parallel --number-of-cores`" jobs):"
function move_files {
  for file in "$@"; do
    echo -n "Moving $file to $destination/"`dirname "$file"`" ... "
    mkdir -p "$destination"/`dirname "$file"`
    \mv -f "$file" "$destination"/`dirname "$file"`/ || echo " fail !" && echo "done."
  done
}
export -f move_files
export destination
find "$soure" -type f "-$days" -print0 | parallel -0 -n 10 move_files

पुनश्च: आपके पास एक टाइपो है, "सूयर" "स्रोत" होना चाहिए। मैंने चर नाम रखा।


0

यह कम सुरुचिपूर्ण है लेकिन आसान है अगर फाइलों की संख्या / आकार बहुत अच्छा नहीं है

अपनी फ़ाइलों को एक zipसंग्रह में एक साथ जिप करें , और फिर -jविकल्प के बिना गंतव्य पर अनज़िप करें । डिफ़ॉल्ट रूप से, ज़िप सापेक्ष निर्देशिका संरचना बनाएगा।


0

इस तरह आजमाएं:

IFS=$'\n'
for f in `find "$soure" -type f -mtime "-$days"`;
do
  mkdir -p "$destination"/`dirname $f`;
  mv $f "$destination"/`dirname $f`;
done

0

क्योंकि ऐसा लगता है कि वास्तव में कोई आसान समाधान नहीं है और मुझे इसकी बहुत आवश्यकता है, मैंने लिनक्स के लिए यह ओपन सोर्स यूटिलिटी बनाई है (अजगर की आवश्यकता है): https://github.com/benapetr/smv

वहाँ कई तरीके हैं कि आप इसे कैसे प्राप्त करने के लिए उपयोग कर सकते हैं जो आपको चाहिए लेकिन शायद सबसे सरल कुछ इस तरह से होगा:

 # -vf = verbose + force (doesn't stop on errors)
smv -vf `find some_folder -type f -mtime "-$days"` target_folder

आप अतिरिक्त रूप से इसे ड्राई मोड में चला सकते हैं ताकि यह कुछ भी न करे लेकिन यह प्रिंट करें कि यह क्या करेगा

smv -rvf `find some_folder -type f -mtime "-$days"` target_folder

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

find "$soure" -type f -mtime "-$days" -exec smv {} "$destination" \;
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.