एक निर्देशिका के तहत सभी निर्देशिकाओं को कम करना


12

मैं एक डायरेक्टरी के तहत हर डाइरेक्टरी के नाम को कम करना चाहता हूं। किन आदेशों के साथ मैं ऐसा कर सकता हूं?

जवाबों:


10

एक स्तर पर सभी निर्देशिकाओं, या पुनरावर्ती?

Zsh

एक स्तर पर:

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!' {} +

कम से कम ओएस एक्स पर यह विफल हो जाएगा यदि कोई निर्देशिका पहले से ही कम मामला है: mv -i a a"mv: a का नाम बदलें a / a: अवैध विवाद"।
Janus

@ जानुस: ठीक है, आपको एक त्रुटि संदेश मिलता है, जो बदसूरत है (हालांकि कमांड लाइन पर हानिरहित है)। लेकिन वैसे भी मुझे zmv का उपयोग करना चाहिए था, जो इस मामले का ध्यान रखता है।
गिल्स एसओ- बुराई को रोकना '

मुझे तब पता चला कि यह -execdirकौन सा भयानक है: unix.stackexchange.com/questions/5412/… तब मैंने पाया कि इसमें कुछ PATHपागलपन है और यह दुखद था :-(
सिरो संतिली 冠状 is 审查 六四 法轮功 法轮功

4

ऐसा एक भी आदेश नहीं है जो ऐसा करेगा, लेकिन आप ऐसा कुछ कर सकते हैं:

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
frabjous

मैं इसके साथ बाहर काम करने के कोशिश कर रहा था find -type d, लेकिन काफी यह नहीं मिल सका
माइकल Mrozek

1
मेरी वृत्ति होती for fd in */;, इस प्रकार यदि वह निर्देशिका होती तो जाँच की आवश्यकता से बचना होता, लेकिन मुझे यह पता नहीं है कि यह वृत्ति अच्छी थी।
स्टीवन डी

हाँ, के लिए ... * / बेहतर होगा।
शॉन जे। गोफ

1
@Shawn: trपहले से ही, एक सीमा उम्मीद तो tr '[A-Z]' '[a-z]'तब्दील [करने के लिए [और ]करने के लिए ]पारित करने में। यह बेकार है लेकिन हानिरहित है; हालांकि उद्धरण के बिना शेल कोष्ठक का विस्तार करेगा यदि वर्तमान निर्देशिका में एक-अपरकेस-अक्षर नाम के साथ एक फ़ाइल थी।
गिल्स एसओ- बुराई को रोकना '

0

मैंने इसे एक-लाइनर चुनौती के रूप में लिया :) सबसे पहले, एक परीक्षण मामला स्थापित करें:

$ 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 -cfind

$ (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। काम करने के उदाहरणों के लिए मेरा जवाब देखें।
गाइल्स का SO- बुराई पर रोक '19

@Giles। धन्यवाद! मैंने आपका mv -iयह लिखने के बाद देखा । उद्धृत करने के साथ अच्छी बात ...
Janus

0

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

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.