UNIX शेल स्क्रिप्टिंग: फ़ाइलों को पुन: एक निर्देशिका में कैसे स्थानांतरित किया जाए?


8

मेरे पास बड़ी संख्या में छोटी फाइलें, एफ, जैसे एक निर्देशिका संरचना में व्यवस्थित हैं:

/A/B/C/f

A के स्तर पर 11 निर्देशिकाएं हैं, प्रत्येक B के स्तर पर लगभग 100 निर्देशिकाओं में से प्रत्येक, C के स्तर पर लगभग 30 निर्देशिकाओं के साथ, प्रत्येक में एक फ़ाइल f के साथ है।

मैं एक स्तर तक सभी फ़ाइलों को कैसे स्थानांतरित करूं? उदाहरण के लिए, फ़ाइलों का यह सेट दिया गया है ...

/ ए / बी / सी / एफ १
/ ए / बी / सी २
/ ए / बी / सी / एफ ३
/ ए / बी / सी / एफ ४

मैं चाहता हूँ कि निर्देशिका में /A/B/f4 के माध्यम से 4 फाइलें, f1 सम्‍मिलित हों। निर्देशिकाओं को हटाना आवश्यक नहीं है।

मैं इस के लिए एक हल समस्या आशा करती हूं कि, संभवतः शामिल find, xargs, और whatnot। कोई विचार?

चीयर्स,

जेम्स

जवाबों:


9

यह GNU खोज (जैसा कि लिनक्स पर पाया जाता है) या समर्थन करने वाले किसी अन्य खोज के साथ काफी सरल है -execdir:

find A -type f -execdir mv -i {} .. \;

एक मानक के साथ find:

find A -type f -exec sh -c 'mv -i "$1" "${1%/*}/.."' sh {} \;

Zsh के साथ:

zmv -Q -o-i 'A/(**/)*/(*)(.)' 'A/$1$2'

यदि निर्देशिका संरचना में हमेशा एक ही घोंसले का स्तर होता है, तो आपको किसी भी पुनरावर्ती ट्रावेल की आवश्यकता नहीं है (लेकिन पहले खाली निर्देशिका निकालें):

for x in */*; do; echo mv -i "$x"/*/* "$x"/..; done

1

फ़ाइलों के उस सेट के लिए, यह होगा:

$ cd /A/B/C/
$ mv ./* ../

लेकिन मुझे उम्मीद है कि आपकी समस्या कुछ और जटिल है ... मैं इसका जवाब नहीं दे सकता ... मुझे यकीन नहीं है कि आपकी dir संरचना कैसी है ... क्या मैं स्पष्ट कर सकता हूं?


यह स्पष्ट रूप से किसी एक निर्देशिका / ए / बी / सी के लिए काम करेगा, लेकिन जैसा कि मेरे पास लगभग 30000 ऐसी निर्देशिकाएं हैं, मैं एक कमांड के लिए उम्मीद कर रहा हूं जिसे एक ही बार में उन सभी की देखभाल करने के लिए पदानुक्रम के शीर्ष पर निष्पादित किया जा सकता है।
jl6

1
@ jl6 मैं देख रहा हूं, और केवल फाइलों को हिलाने की जरूरत है? इसलिए C को B, और B से A तक नहीं जाना है, आदि ...
Stack Overflow is dead

यह सही है - ऑपरेशन केवल फाइलों पर किया जाना चाहिए, पदानुक्रम के निम्नतम स्तर पर, और उन्हें केवल एक स्तर ऊपर ले जाना चाहिए।
23

0

मेरा पहला अनुमान है

$ find A -type f -exec mv {} .. \;  

जब तक आप निर्दिष्ट नहीं करते तब तक -depthयह ठीक होना चाहिए। मैंने इसे करने की कोशिश नहीं की है, इसलिए इसे करने से पहले इसे पहले परख लें।


जब दो फाइलें एक ही नाम की हों तो क्या करें?

ढूँढें समस्या नहीं है, imbedded "mv" कमांड है। डुप नाम अच्छे नहीं होंगे क्योंकि एमवी का नाम बदलने वाला नहीं है, यह ओवरराइट करने वाला है। आप थोड़ी मदद करने के लिए mv -i का उपयोग कर सकते हैं, लेकिन 30,000+ फाइलों के साथ जो दर्दनाक हो सकती हैं। यदि आपको उस स्थिति पर अधिक नियंत्रण रखने की आवश्यकता है, तो आपको एक स्क्रिप्टिंग भाषा में लिखे गए प्रोग्राम की आवश्यकता हो सकती है (मेरी पसंद अजगर, वाईएमएमवी होगी)।
22

मैंने mv के साथ "बैकअप" का उपयोग नहीं किया है, लेकिन मैन पेज को देखकर ऐसा लग रहा है कि यह आपके नाम की समस्या का समाधान हो सकता है। "a -type f -exec mv --backup गिने {} .. \;" काम कर सकते हैं (ध्यान दें कि
--बैकअप

दिए गए खोज उदाहरण ए से ऊपर एक निर्देशिका में सभी फाइलों को निम्नतम स्तर पर ले जाएगा (मुझे विश्वास है कि ".." को शेल / एमवी को खोजने के लिए पारित होने से पहले शेल द्वारा व्याख्या की जा रही है?)। मुझे पदानुक्रम में केवल एक स्तर ऊपर ले जाने के लिए फ़ाइलों की आवश्यकता है। एक और स्पष्टीकरण: कोई डुप्लिकेट फ़ाइल नाम नहीं होगा, जब तक कि फाइलें केवल एक स्तर ऊपर ले जाती हैं।
22

@hotei: mvआदेशों को वर्तमान निर्देशिका में निष्पादित किया जाता है, इसलिए ..आप जो आशा करते हैं वह नहीं करता है। समाधान के लिए मेरा जवाब देखें । @ jl6: शेल का कोई लेना देना नहीं है .., यह कर्नेल द्वारा नियंत्रित किया जाता है।
गिल्स एसओ- बुराई को रोकें

0

आप केवल उस पत्ती निर्देशिका में हैं (यानी आप ले जाना नहीं चाहते फ़ाइलों को स्थानांतरित करना चाहते हैं /A/B/fileके लिए /Aहै, तो Bउपनिर्देशिका होता है) तो यहाँ तरीके कि ऐसा करने के लिए के एक जोड़े हैं:

दोनों को इसकी आवश्यकता है

leaf ()
{
    find $1 -depth -type d | sed 'h; :b; $b; N; /^\(.*\)\/.*\n\1$/ { g; bb }; $ {x; b}; P; D'
}
shopt -s nullglob

यह एक काम करता है:

leaf A | while read -r dir
do
    for file in "$dir"/*
    do
        parent=${dir%/*}
        if [[ -e "$parent/${file##*/}" ]]
        then
            echo "not moved: $file"
        else
            mv "$file" "$parent"
        fi
    done
done

यह तेज़ होगा, लेकिन यह खाली स्रोत निर्देशिकाओं को पसंद नहीं करता है:

leaf A | while read -r dir
do
    mv -n "${dir}"/* "${dir%/*}"
    remains=$(echo "$dir"/*)
    [[ -n "$remains" ]] && echo "not moved: $remains"
done
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.