मैंने इसे फिर से करने के लिए दिल नहीं किया है, लेकिन मैंने कमांडलाइन फाइंड सेड एक्सक के जवाब में यह लिखा है । वहाँ पूछने वाला जानना चाहता था कि एक पूरे पेड़ को कैसे स्थानांतरित किया जाए, संभवतः एक निर्देशिका या दो को छोड़कर, और स्ट्रिंग वाली सभी फ़ाइलों और निर्देशिकाओं का नाम बदलें। "पुराने" के बजाय करने के लिए होते हैं "नई" ।
के अतिरिक्त श्रमसाध्य क्रिया के साथ कैसे का वर्णन करने केनीचे , यह विधि इस भी अद्वितीय हो सकती है कि इसमें अंतर्निर्मित डीबगिंग शामिल है। यह मूल रूप से लिखे गए संकलन के अलावा कुछ भी नहीं करता है और एक चर को बचाने के लिए सभी आज्ञाओं को मानता है जो यह अनुरोध किए गए कार्य को करने के लिए करना चाहिए।
यह स्पष्ट रूप से यथासंभव छोरों से बचा जाता है। इसके अतिरिक्त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}जिसकी जांच समारोह के बाहर की जा सकती है।
ठंडा।
-माइक