जवाबों:
एक स्तर पर सभी निर्देशिकाओं, या पुनरावर्ती?
एक स्तर पर:
autoload zmv
zmv -o-i -Q 'root/(*)(/)' 'root/${1:l}'
रिकर्सिवली:
zmv -o-i -Q 'root/(**/)(*)(/)' 'root/$1${2:l}'
स्पष्टीकरण: zmv
दिए गए प्रतिस्थापन पाठ के अनुसार एक पैटर्न से मेल खाती फ़ाइलों का नाम बदल देता है। हुड के नीचे प्रत्येक कमांड -o-i
का -i
विकल्प पास करता है mv
(नीचे देखें)। प्रतिस्थापन पाठ में $1
, $2
आदि, पैटर्न में क्रमिक कोष्ठक समूह हैं। **
सभी (उप) * निर्देशिका का मतलब है, पुनरावर्ती। अंतिम (/)
एक कोष्ठक समूह नहीं है, लेकिन केवल निर्देशिका से मेल खाने वाला एक ग्लोब क्वालीफायर अर्थ है। लोअरकेस में ${2:l}
कनवर्ट करता $2
है।
एक स्तर पर:
for x in root/*/; do mv -i "$x" "$(printf %s "$x" | tr '[:upper:]' '[:lower:]')"; done
अंतिम /
मिलानों को निर्देशिकाओं तक सीमित कर mv -i
देता है , और टकराव के मामले में पुष्टि करने के लिए कहता है। -i
एक टक्कर के मामले में ओवरराइट करने के लिए निकालें , और उपयोग करें yes n | for …
। टालमटोल नहीं किया जाएगा और न ही कोई ऐसा नामकरण किया जाएगा जो टकराएगा।
रिकर्सिवली:
find root/* -depth -type d -exec sh -c '
t=${0%/*}/$(printf %s "${0##*/}" | tr "[:upper:]" "[:lower:]");
[ "$t" = "$0" ] || mv -i "$0" "$t"
' {} \;
यह -depth
सुनिश्चित करता है कि गहरी नेस्टेड निर्देशिकाओं को उनके पूर्वजों से पहले संसाधित किया जाता है। नाम प्रसंस्करण एक होने के नाते पर निर्भर करता है /
; यदि आप वर्तमान निर्देशिका में संचालन को कॉल करना चाहते हैं, तो उपयोग करें ./*
(सामना करने के लिए शेल स्क्रिप्ट को अपनाना .
या *
पाठक के लिए एक अभ्यास के रूप में छोड़ दिया गया है)।
यहाँ मैं पर्ल नाम का स्क्रिप्ट का उपयोग करता हूं जो डेबियन और उबंटू जहाज के रूप में /usr/bin/prename
(आमतौर पर उपलब्ध है rename
)। एक स्तर पर:
rename 's!/([^/]*/?)$!\L/$1!' root/*/
पुनरावर्ती, बैश or4 या zsh के साथ:
shopt -s globstar # only in bash
rename 's!/([^/]*/?)$!\L/$1!' root/**/*/
पुनरावर्ती, सुस्पष्ट रूप से:
find root -depth -type d -exec rename -n 's!/([^/]*/?)$!\L/$1!' {} +
-execdir
कौन सा भयानक है: unix.stackexchange.com/questions/5412/… तब मैंने पाया कि इसमें कुछ PATH
पागलपन है और यह दुखद था :-(
ऐसा एक भी आदेश नहीं है जो ऐसा करेगा, लेकिन आप ऐसा कुछ कर सकते हैं:
for fd in */; do
#get lower case version
fd_lower=$(printf %s "$fd" | tr A-Z a-z)
#if it wasn't already lowercase, move it.
[ "$fd" != "$fd_lower" ] && mv "$fd" "$fd_lower"
done
यदि आपको इसे मजबूत करने की आवश्यकता है, तो आपको उस समय के लिए ध्यान देना चाहिए जब पहले से ही दो निर्देशिकाएं हैं जो केवल मामले में भिन्न हैं।
एक-लाइनर के रूप में:
for fd in */; do fd_lower=$(printf %s "$fd" | tr A-Z a-z) && [ "$fd" != "$fd_lower" ] && mv "$fd" "$fd_lower"; done
for file in * ; do if [ -d "$file" ] ; then dest="$(echo $file | sed y/ABCDEFGHIJKLMNOPQRSTUVWXYZ/abcdefghijklmnopqrstuvwxyz/)" ; [ "$dest" != "$file" ] && mv "$file" "$dest" ; fi ; done
find -type d
, लेकिन काफी यह नहीं मिल सका
for fd in */;
, इस प्रकार यदि वह निर्देशिका होती तो जाँच की आवश्यकता से बचना होता, लेकिन मुझे यह पता नहीं है कि यह वृत्ति अच्छी थी।
tr
पहले से ही, एक सीमा उम्मीद तो tr '[A-Z]' '[a-z]'
तब्दील [
करने के लिए [
और ]
करने के लिए ]
पारित करने में। यह बेकार है लेकिन हानिरहित है; हालांकि उद्धरण के बिना शेल कोष्ठक का विस्तार करेगा यदि वर्तमान निर्देशिका में एक-अपरकेस-अक्षर नाम के साथ एक फ़ाइल थी।
मैंने इसे एक-लाइनर चुनौती के रूप में लिया :) सबसे पहले, एक परीक्षण मामला स्थापित करें:
$ for d in foo Bar eVe; do mkdir -p dcthis/$d; touch dcthis/a${d}.txt; done
$ ls dcthis/
Bar aBar.txt aeVe.txt afoo.txt eVe foo
मैं find
अपरकेस अक्षरों के साथ निर्देशिकाओं को स्पॉट करने के लिए उपयोग करता हूं और फिर उनके माध्यम से डाउनकेस करता हूं । अनुमान लगाना थोड़ा हैक-ईश है, लेकिन जब मैं सीधे चीजों के लिए भागने की कोशिश करता हूं तो मेरा सिर हमेशा फट जाता है।sh -c 'mv {}
echo {} | tr [:upper:] [:lower:]
'sh -c
find
$ (cd dcthis && find . -maxdepth 1 -type d -path '*[A-Z]*' -exec sh -c 'mv {} `echo {} | tr [:upper:] [:lower:]`' \;)
$ ls dcthis/
aBar.txt aeVe.txt afoo.txt bar eve foo
सावधान रहें: यह समाधान यह जांच नहीं करता है कि डाउनकास्टिंग टकराव की ओर जाता है या नहीं!
mv -i
:। एक बड़ी समस्या यह है कि आपने उचित उद्धरण का उपयोग नहीं किया है, इसलिए \[*?
नाम में कहीं भी विशेष वर्ण (व्हाट्सएप या ) होने पर आपकी कमांड विफल हो जाएगी । find
पुनरावृत्ति होने तक उपयोग करने का कोई मतलब नहीं है , और फिर आपको ज़रूरत है find -depth
, और -path
होना चाहिए -name
। काम करने के उदाहरणों के लिए मेरा जवाब देखें।
mv -i
यह लिखने के बाद देखा । उद्धृत करने के साथ अच्छी बात ...
find -execdir
| नाम बदलने
यह इसे करने के लिए सबसे अच्छा तरीका होगा यदि यह सापेक्ष पथ पागलपन के लिए नहीं थे, क्योंकि यह पर्ल रेगेक्स फू से बचता है केवल बेसन पर कार्य करने के लिए:
PATH="$(echo "$PATH" | sed -E 's/(^|:)[^\/][^:]*//g')" \
find a -depth -execdir rename 's/(.*)/\L$1/' '{}' \;
-execdir
पहले cd
केवल basename पर निष्पादित करने से पहले निर्देशिका में है।
दुर्भाग्य से, मैं उस PATH
हैकिंग भाग से छुटकारा नहीं पा सकता हूं , find -execdir
यदि आपके पास एक रिश्तेदार पथ है तो कुछ भी करने से इनकार कर देता है PATH
...: /ubuntu/621132/why-use-the-execdir-action- है-असुरक्षित गैर-निर्देशिका-जो-है-में-पथ / 1109378 # 1109378
mv -i a a
"mv: a का नाम बदलें a / a: अवैध विवाद"।