मैंने इसे फिर से करने के लिए दिल नहीं किया है, लेकिन मैंने कमांडलाइन फाइंड सेड एक्सक के जवाब में यह लिखा है । वहाँ पूछने वाला जानना चाहता था कि एक पूरे पेड़ को कैसे स्थानांतरित किया जाए, संभवतः एक निर्देशिका या दो को छोड़कर, और स्ट्रिंग वाली सभी फ़ाइलों और निर्देशिकाओं का नाम बदलें। "पुराने" के बजाय करने के लिए होते हैं "नई" ।
के अतिरिक्त श्रमसाध्य क्रिया के साथ कैसे का वर्णन करने केनीचे , यह विधि इस भी अद्वितीय हो सकती है कि इसमें अंतर्निर्मित डीबगिंग शामिल है। यह मूल रूप से लिखे गए संकलन के अलावा कुछ भी नहीं करता है और एक चर को बचाने के लिए सभी आज्ञाओं को मानता है जो यह अनुरोध किए गए कार्य को करने के लिए करना चाहिए।
यह स्पष्ट रूप से यथासंभव छोरों से बचा जाता है। इसके अतिरिक्तsed
पैटर्न के एक से अधिक मिलान के लिए पुनरावर्ती खोज के जहाँ तक मुझे पता है कोई अन्य पुनरावृत्ति नहीं है।
और अंतिम, यह पूरी तरह से है null
सीमांकित है - यह किसी भी फ़ाइल नाम के किसी भी चरित्र पर यात्रा को छोड़कर नहीं है null
। मुझे नहीं लगता कि आपके पास ऐसा होना चाहिए।
वैसे, यह वास्तव में तेजी से है। देखो:
% _mvnfind() { mv -n "${1}" "${2}" && cd "${2}"
> read -r SED <<SED
> :;s|${3}\(.*/[^/]*${5}\)|${4}\1|;t;:;s|\(${5}.*\)${3}|\1${4}|;t;s|^[0-9]*[\t]\(mv.*\)${5}|\1|p
> SED
> find . -name "*${3}*" -printf "%d\tmv %P ${5} %P\000" |
> sort -zg | sed -nz ${SED} | read -r ${6}
> echo <<EOF
> Prepared commands saved in variable: ${6}
> To view do: printf ${6} | tr "\000" "\n"
> To run do: sh <<EORUN
> $(printf ${6} | tr "\000" "\n")
> EORUN
> EOF
> }
% rm -rf "${UNNECESSARY:=/any/dirs/you/dont/want/moved}"
% time ( _mvnfind ${SRC=./test_tree} ${TGT=./mv_tree} \
> ${OLD=google} ${NEW=replacement_word} ${sed_sep=SsEeDd} \
> ${sh_io:=sh_io} ; printf %b\\000 "${sh_io}" | tr "\000" "\n" \
> | wc - ; echo ${sh_io} | tr "\000" "\n" | tail -n 2 )
<actual process time used:>
0.06s user 0.03s system 106% cpu 0.090 total
<output from wc:>
Lines Words Bytes
115 362 20691 -
<output from tail:>
mv .config/replacement_word-chrome-beta/Default/.../googlestars \
.config/replacement_word-chrome-beta/Default/.../replacement_wordstars
नोट: ऊपर function
की संभावना के GNU
संस्करणों की आवश्यकता होगी sed
और find
ठीक से संभाल करने के लिएfind printf
और sed -z -e
और:;recursive regex test;t
कॉल। यदि ये आपके लिए उपलब्ध नहीं हैं, तो कार्यक्षमता को कुछ मामूली समायोजन के साथ दोहराया जा सकता है।
यह वह सब कुछ करना चाहिए जो आप शुरू से अंत तक बहुत कम उपद्रव के साथ करना चाहते थे। मैंने fork
साथ दिया था sed
, लेकिन मैं कुछ sed
पुनरावर्ती शाखाओं में बँधने का अभ्यास भी कर रहा था, इसलिए मैं यहाँ हूँ। यह एक नाई के स्कूल में एक छूट बाल कटवाने की तरह है, मुझे लगता है। यहाँ वर्कफ़्लो है:
rm -rf ${UNNECESSARY}
- मैंने जानबूझकर कोई भी कार्यात्मक कॉल छोड़ा है जो किसी भी प्रकार के डेटा को हटा या नष्ट कर सकता है। आप उल्लेख करते हैं कि
./app
अवांछित हो सकता है। इसे हटाएं या इसे पहले से कहीं और स्थानांतरित करें, या, वैकल्पिक रूप से, आप इसे \( -path PATTERN -exec rm -rf \{\} \)
नियमित रूप से find
प्रोग्राम करने के लिए एक रूटीन में बना सकते हैं , लेकिन यह सब आपका है।
_mvnfind "${@}"
- इसके तर्कों की घोषणा करें और कार्यकर्ता फ़ंक्शन को कॉल करें।
${sh_io}
इसमें विशेष रूप से महत्वपूर्ण है कि यह फ़ंक्शन से रिटर्न बचाता है। ${sed_sep}
एक सेकंड में आता है; यह एक मनमाना स्ट्रिंग sed
है जो फ़ंक्शन में पुनरावृत्ति को संदर्भित करने के लिए उपयोग किया जाता है । यदि ${sed_sep}
किसी ऐसे मूल्य पर सेट किया गया है जो संभवतः आपके किसी भी पथ में पाया जा सकता है- या फ़ाइल-नामों पर कार्य किया गया है ... ठीक है, बस इसे न होने दें।
mv -n $1 $2
- पूरे पेड़ को शुरू से ही स्थानांतरित कर दिया गया है। यह बहुत सारे सिरदर्द को बचाएगा; मुझ पर विश्वास करो। बाकी जो आप करना चाहते हैं - नाम बदलना - बस फाइलसिस्टम मेटाडेटा का मामला है। यदि आप, उदाहरण के लिए, इसे एक ड्राइव से दूसरे में, या किसी भी प्रकार की फ़ाइल सिस्टम सीमाओं में स्थानांतरित कर रहे हैं, तो आप एक बार एक कमांड के साथ ऐसा करना बेहतर समझते हैं। यह भी सुरक्षित है। के
-noclobber
लिए निर्धारित विकल्प पर ध्यान दें mv
; जैसा कि लिखा गया है, यह फ़ंक्शन उस जगह पर नहीं रखा जाएगा ${SRC_DIR}
जहां ${TGT_DIR}
पहले से मौजूद है।
read -R SED <<HEREDOC
- मैंने सभी सीड्स कमांड्स को यहां रखा है ताकि वे झंझटों से बच सकें और नीचे चरने के लिए उन्हें चर में पढ़ सकें। नीचे स्पष्टीकरण।
find . -name ${OLD} -printf
- हम
find
प्रक्रिया शुरू करते हैं। साथ find
हम केवल कुछ भी है कि नाम बदलने की जरूरत है क्योंकि हम पहले से ही जगह-टू-जगह के सभी किया था के लिए खोज mv
समारोह का पहला आदेश के साथ आपरेशनों। उदाहरण के लिए, कॉल की find
तरह कोई प्रत्यक्ष कार्यवाही करने के exec
बजाय, हम इसका उपयोग कमांड-लाइन को गतिशील रूप से बनाने के लिए करते हैं -printf
।
%dir-depth :tab: 'mv '%path-to-${SRC}' '${sed_sep}'%path-again :null delimiter:'
find
उन फ़ाइलों का पता लगाने के बाद, जिनकी हमें सीधे आवश्यकता होती है और कमांड ( अधिकांश ) को प्रिंट करता है , जिन्हें हमें आपके नाम बदलने की प्रक्रिया की आवश्यकता होगी। %dir-depth
हमला बोला पर प्रत्येक पंक्ति के आरंभ सुनिश्चित करने के लिए हम एक माता पिता वस्तु है कि अभी तक का नाम बदलने की के साथ एक फ़ाइल या पेड़ में निर्देशिका का नाम बदलने की कोशिश नहीं कर रहे मदद मिलेगी। find
अपने फाइलसिस्टम ट्री को चलने के लिए सभी प्रकार की अनुकूलन तकनीकों का उपयोग करता है और यह एक निश्चित बात नहीं है कि यह उन डेटा को लौटाएगा जो हमें एक सुरक्षित-संचालन संचालन के लिए चाहिए। यही कारण है कि हम अगले ...
sort -general-numerical -zero-delimited
- हम सभी के
find
उत्पादन को आधार पर क्रमबद्ध करते हैं %directory-depth
ताकि $ {SRC} के संबंध में निकटतम पथ पहले काम कर सकें। यह mv
गैर-मौजूद स्थानों में फ़ाइलों को शामिल करने वाली संभावित त्रुटियों से बचा जाता है , और यह पुनरावर्ती लूपिंग के लिए आवश्यकता को कम करता है। ( वास्तव में, आप एक लूप खोजने के लिए कठोर हो सकते हैं )
sed -ex :rcrs;srch|(save${sep}*til)${OLD}|\saved${SUBSTNEW}|;til ${OLD=0}
- मुझे लगता है कि यह पूरी स्क्रिप्ट में एकमात्र लूप है, और यह केवल
%Path
प्रत्येक स्ट्रिंग के लिए दूसरे मुद्रित पर लूप करता है अगर इसमें एक से अधिक $ {OLD} मान होता है जिसे प्रतिस्थापित करने की आवश्यकता हो सकती है। अन्य सभी समाधानों की मैंने कल्पना की है कि इसमें एक दूसरी sed
प्रक्रिया शामिल है , और जबकि एक छोटा लूप वांछनीय नहीं हो सकता है, निश्चित रूप से यह स्पानिंग को धड़कता है और एक पूरी प्रक्रिया को भूल जाता है।
- तो मूल रूप से क्या
sed
यहाँ $ {sed_sep} की खोज की जाती है, फिर, इसे पाए जाने पर, इसे सहेजता है और यह सभी वर्णों का सामना करता है जब तक कि इसे $ {OLD} नहीं मिल जाता है, जो इसके बाद $ {NEW} से बदल जाता है। यह तब $ {sed_sep} पर वापस जाता है और $ {OLD} के लिए फिर से दिखता है, अगर यह स्ट्रिंग में एक से अधिक बार होता है। यदि यह नहीं पाया जाता है, तो यह संशोधित स्ट्रिंग को प्रिंट करता है stdout
(जो इसे फिर अगले पकड़ता है) और लूप को समाप्त करता है।
- यह पूरी स्ट्रिंग को पार्स करने से बचता है, और यह सुनिश्चित करता है कि
mv
कमांड स्ट्रिंग की पहली छमाही , जिसमें $ {OLD} को शामिल करना आवश्यक है, इसमें शामिल है, और दूसरी छमाही को बदलने के लिए जितनी बार आवश्यक है उतनी बार बदल दिया जाता है $ {OLD} नाम mv
गंतव्य पथ से।
sed -ex...-ex search|%dir_depth(save*)${sed_sep}|(only_saved)|out
- यहाँ दो
-exec
कॉल एक दूसरे के बिना होते हैं fork
। पहले में, जैसा कि हमने देखा है, हम mv
कमांड को find
'' -printf
फंक्शन कमांड '' द्वारा दिए गए आवश्यकतानुसार संशोधित करते हैं, ताकि $ {OLD} के सभी संदर्भों को $ {NEW} में ठीक से बदल सकें, लेकिन ऐसा करने के लिए हमें कुछ का उपयोग करना होगा मनमाना संदर्भ बिंदु जो अंतिम आउटपुट में शामिल नहीं होना चाहिए। इसलिए एक बार जब sed
इसे पूरा करने की आवश्यकता होती है, तो हम इसे पास करने से पहले होल्ड-बफर से इसके संदर्भ बिंदुओं को मिटा देने का निर्देश देते हैं।
और अब हम वापस आ गए हैं
read
एक कमांड मिलेगा जो इस तरह दिखता है:
% mv /path2/$SRC/$OLD_DIR/$OLD_FILE /same/path_w/$NEW_DIR/$NEW_FILE \000
यह read
उस ${msg}
रूप में होगा ${sh_io}
जिसकी जांच समारोह के बाहर की जा सकती है।
ठंडा।
-माइक