सपाट निर्देशिका लेकिन नई फ़ाइल नाम में निर्देशिका नामों को संरक्षित करें


11

मैं निम्नलिखित प्रारूप में एक निर्देशिका को कैसे समतल कर सकता हूं?

इससे पहले: ./aaa/bbb/ccc.png

उपरांत: ./aaa-bbb-ccc.png


पुनश्च: कृपया विषम वर्णों (जैसे रिक्त स्थान) के साथ फ़ाइल नामों के लिए भी ध्यान दें
नाथन जेबी

3
आपको यह भी निर्दिष्ट करना होगा कि आप कैसे संभव मामले को संभालना चाहते हैं जहां ./foo/bar/baz.pngऔर ./foo-bar-baz.pngदोनों मौजूद हैं। मुझे लगता है कि आप बाद वाले को पूर्व से बदलना नहीं चाहते हैं?
jw013

मेरे एक मामले में, यह अप्रासंगिक है, लेकिन इसका जवाब वास्तव में इस बात के लिए होना चाहिए कि दूसरे इस पर भरोसा कर सकें! धन्यवाद!
नाथन जेबी

जवाबों:


7

चेतावनी: मैंने इनमें से अधिकांश कमांड सीधे अपने ब्राउज़र में टाइप किए। कैवेट लेक्टर।

Zsh और zmv के साथ :

zmv -o -i -Qn '(**/)(*)(D)' '${1//\//-}$2'

स्पष्टीकरण: पैटर्न **/*वर्तमान निर्देशिका की उपनिर्देशिकाओं में सभी फ़ाइलों से मेल खाता है, पुनरावर्ती रूप से (यह वर्तमान निर्देशिका में फ़ाइलों से मेल नहीं खाता है, लेकिन इनका नाम बदलने की आवश्यकता नहीं है)। कोष्ठक के पहले दो जोड़े ऐसे समूह हैं जिन्हें प्रतिस्थापन पाठ के रूप में $1और संदर्भित किया जा सकता है $2। कोष्ठक की अंतिम जोड़ी D ग्लोब क्वालीफायर को जोड़ती है ताकि डॉट फाइलें लोप न हों। विकल्प -o -iको पास करने का मतलब है ताकि आपको संकेत -iदिया mvजाए कि क्या कोई मौजूदा फ़ाइल अधिलेखित की जाएगी।


केवल POSIX टूल के साथ:

find . -depth -exec sh -c '
    for source; do
      case $source in ./*/*)
        target="$(printf %sz "${source#./}" | tr / -)";
        mv -i -- "$source" "${target%z}";;
      esac
    done
' _ {} +

स्पष्टीकरण: caseकथन वर्तमान निर्देशिका और वर्तमान निर्देशिका के शीर्ष-स्तरीय उपनिर्देशिकाओं को छोड़ देता है। targetस्रोत फ़ाइल नाम शामिल है ( $0) प्रमुख ./छीन लिया और डैश के साथ सभी स्लैशों के साथ, एक अंतिम zzयदि फ़ाइल नाम एक नई सीमा के साथ समाप्त होता है, तो अंतिम होता है: अन्यथा कमांड प्रतिस्थापन इसे बंद कर देगा।

यदि आपका findसमर्थन नहीं करता है -exec … +(OpenBSD, मैं आपको देख रहा हूं):

find . -depth -exec sh -c '
    case $0 in ./*/*)
      target="$(printf %sz "${0#./}" | tr / -)";
      mv -i -- "$0" "${target%z}";;
    esac
' {} \;

बैश (या ksh93) के साथ, आपको डैश द्वारा स्लैश को बदलने के लिए किसी बाहरी कमांड को कॉल करने की आवश्यकता नहीं है, आप स्ट्रिंग प्रतिस्थापन निर्माण के साथ ksh93 पैरामीटर विस्तार का उपयोग कर सकते हैं ${VAR//STRING/REPLACEMENT}:

find . -depth -exec bash -c '
    for source; do
      case $source in ./*/*)
        source=${source#./}
        target="${source//\//-}";
        mv -i -- "$source" "$target";;
      esac
    done
' _ {} +

for sourceउदाहरण पहले प्रस्तुत फ़ाइल / dir याद आती है ... मैं अंत में पता चला गया है तुम क्यों (सामान्य रूप से) का इस्तेमाल किया है _के रूप में $0महान जवाब के लिए धन्यवाद :) ... और। मैं उनसे बहुत कुछ सीखता हूं।
पीटर।

ध्यान दें कि zmv उदाहरण सिर्फ एक ड्राई रन करता है: यह चाल कमांड को प्रिंट करता है लेकिन यह उन्हें निष्पादित नहीं करता है। वास्तव में उन कमांड को निष्पादित करने के लिए, n -Qn में निकालें।
पीटर

5

जबकि यहाँ पहले से ही अच्छे उत्तर हैं, मुझे यह अधिक सहज लगता है, भीतर bash:

find aaa -type f -exec sh -c 'new=$(echo "{}" | tr "/" "-" | tr " " "_"); mv "{}" "$new"' \;

aaaआपकी मौजूदा निर्देशिका कहां है इसमें मौजूद फ़ाइलों को वर्तमान निर्देशिका में ले जाया जाएगा (केवल आहा में खाली निर्देशिकाओं को छोड़कर)। दोनों कॉल trदोनों निर्देशिकाओं और रिक्त स्थान को संभालने के लिए (बच गए स्लैश के लिए तर्क के बिना - पाठक के लिए एक व्यायाम)।

मैं इसे अधिक सहज और अपेक्षाकृत आसान मानता हूं। यानी मैं findमापदंडों को बदल सकता हूं अगर मैं केवल .png फ़ाइलों को ढूंढना चाहता हूं। मैं trकॉल बदल सकता हूं , या आवश्यकतानुसार जोड़ सकता हूं । और मैं echoइससे पहले जोड़ सकता हूं mvअगर मैं नेत्रहीन जांच करना चाहता हूं कि यह सही काम करेगा (तब अतिरिक्त के बिना दोहराएं echoयदि चीजें सही दिखती हैं:

find aaa -name \*.png -exec sh -c 'new=$(echo "{}" | tr "/" "-" | tr " " "_"); echo mv "{}" "$new"' \;

ध्यान दें कि मैं उपयोग कर रहा हूं find aaa... और find .... या find aaa/... जैसा कि बाद के दो अंतिम फ़ाइल नाम में अजीब कलाकृतियों को छोड़ देगा।


इस एक लाइनर के लिए धन्यवाद - यह मेरे लिए अच्छी तरह से काम करता था जब मैंने इसे निर्देशिका के बाहर से किया था (जो कि आपने ऐसा करने के लिए कहा था)। जब मैंने निर्देशिका के अंदर से करने की कोशिश की (जड़ निर्देशिका नाम से बचने की उम्मीद की जा रही है) सभी फाइलें "गायब" हो गईं। मैंने उन्हें उसी निर्देशिका में छिपी फाइलों में बदल दिया था।
dgig

2
find . -mindepth 2 -type f -name '*' |
  perl -l000ne 'print $_;  s/\//-/g; s/^\.-/.\// and print' |
    xargs -0n2 mv 

नोट: यह फ़ाइल नाम के लिए काम नहीं करेगा जिसमें शामिल हैं \n
यह जाहिर है केवल प्रकार से चलता है fफ़ाइलें ...
केवल नाम संघर्ष फाइलों से होगा में पहले से मौजूद लोक निर्माण विभाग

इस मूल उपसमूह के साथ परीक्षण किया गया

rm -fr junk
rm -f  junk*hello*

mkdir -p  junk/junkier/junkiest
touch    'hello    hello'
touch    'junk/hello    hello'
touch    'junk/junkier/hello    hello'
touch    'junk/junkier/junkiest/hello    hello'

जिसके परिणामस्वरूप

./hello    hello
./junk-hello    hello
./junk-junkier-hello    hello
./junk-junkier-junkiest-hello    hello

0

यहाँ एक lsसंस्करण है .. टिप्पणियाँ स्वागत है। यह इस तरह के अजीब फ़ाइलनाम के लिए काम करता है "j1ळ\n\001\n/j2/j3/j4/\nh  h\n", लेकिन मैं वास्तव में किसी भी नुकसान के बारे में जानना चाहता हूं। यह " lsवास्तव में दुर्भावनापूर्ण रूप से ऐसा कर सकता है ?"

ls -AbQR1p * |                        # paths in "quoted" \escaped format
    sed -n '/":$/,${/.[^/]$/p}' |     # skip files in pwd, blank and dir/ lines
    { bwd="$PWD"; while read -n1;     # save base dir strip leading "quote
                        read -r p; do # read path
        printf -vs "${p%\"*}"         # strip trailing quote"(:)
        [[ $p == *: ]] && {           # this is a directory
            cd   "$bwd/$s"            # change into new directory
            rnp="${s//\//-}"-         # relative name prefix
        } || mv "$s" "$bwd/$rnp$s"
      done; }

-1

बस trकमांड के लिए फ़ाइल नाम + पथ को पाइप करें ।tr <replace> <with>

for FILE in `find aaa -name "*.png"`
do
  NEWFILE=`echo $FILE | tr '/' '-'`
  cp -v $FILE $NEWFILE
done

1
यह अजीब फ़ाइलनाम को सुरक्षित रूप से नहीं संभालता है। रिक्त स्थान इसे (अन्य चीजों के बीच) तोड़ देंगे।
jw013

पहली नज़र में, यह एक साफ, पठनीय समाधान है, लेकिन @ jw013 सही है, यह अच्छी तरह से रिक्त स्थान को संभाल नहीं पाएगा। मदद cpकरने के लिए लाइन बदलना होगा cp -v "$FILE" "$NEWFILE"? (इसके अलावा, आपको केवल पीएनजी फाइलें नहीं माननी चाहिए।)
नाथन जेबी

2
@ NathanJ.Brauer cpलाइन में उद्धरण जोड़ना अपर्याप्त है। लूप के findसाथ पार्सिंग आउटपुट का संपूर्ण दृष्टिकोण forत्रुटिपूर्ण है। उपयोग करने के लिए केवल सुरक्षित तरीके findहैं -exec, या -print0यदि उपलब्ध हो (कम से कम पोर्टेबल -exec)। मैं एक और अधिक मजबूत विकल्प का सुझाव देता हूं, लेकिन आपका प्रश्न फिलहाल निर्दिष्ट है।
jw013

-2

फ़ाइल नाम में रिक्त स्थान के लिए सुरक्षित:

#!/bin/bash

/bin/find $PWD -type f | while read FILE
do
    _new="${FILE//\//-}"
    _new="${_new:1}"
    #echo $FILE
    #echo $_new

    /bin/mv "$FILE" "$_new"
done

स्पष्ट कारणों के cpबजाय के साथ खदान mv, लेकिन उसी का उत्पादन करना चाहिए।


3
type find-> find is /usr/bin/findमेरी मशीन पर। PATHएक स्क्रिप्ट में एक चर नाम के रूप में उपयोग करना एक भयानक विचार है। इसके अलावा, आपकी स्क्रिप्ट रिक्त स्थान या बैकस्लैश के साथ नाम दर्ज करती है, क्योंकि आप readकमांड का दुरुपयोग करते हैं (इस साइट को खोजें IFS read -r)।
गिल्स एसओ-

find is hashed (/bin/find), प्रासंगिक कैसे? अलग डिस्ट्रॉर्स अलग हैं?
टिम

मुझे पता था कि इस से दूर रहना चाहिए था, गिद्ध चारा।
टिम

@ समय आप अपने प्रतिनिधि को वापस पाने के लिए जवाब को हमेशा के लिए हटा सकते हैं (और मेरा और साथ ही b / c इसे डाउनवोट करने के लिए रिपीट खर्च करता है)। स्क्रिप्ट में हार्ड-कोडिंग पथ से लगता है कि आप PATHपर्यावरण चर के बिंदु को याद कर रहे हैं , जो कि हर यूनिक्स प्रणाली का उपयोग करता है। यदि आप लिखते हैं, /bin/findतो आपकी स्क्रिप्ट वास्तव में हर सिस्टम पर टूटी हुई है (गिल्स, मेरा, और शायद ओपी का) जो नहीं है /bin/find(जैसे b / c यह है /usr/bin/find)। PATHपर्यावरण चर का पूरा बिंदु इसे गैर-मुद्दा बनाना है।
jw013

वैसे, $(pwd)पहले से ही एक चर में उपलब्ध है $PWD:। लेकिन आपको यहां एक निरपेक्ष पथ का उपयोग नहीं करना चाहिए : यदि आपकी स्क्रिप्ट को कहा जाता है /home/tim, तो इसका नाम बदलने /home/tim/some/pathका प्रयास किया जाता है /home-tim-some-path
गिल्स एसओ- बुराई को रोकना '
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.