बैश स्क्रिप्ट का उपयोग करके फ़ाइल नामों में रिक्त स्थान कैसे बदलें


264

किसी दिए गए रूट निर्देशिका से शुरू होने वाले फ़ाइल और निर्देशिका नामों में अंडरस्कोर के साथ रिक्त स्थान को बदलने के लिए क्या कोई सुरक्षित समाधान सुझा सकता है? उदाहरण के लिए:

$ tree
.
|-- a dir
|   `-- file with spaces.txt
`-- b dir
    |-- another file with spaces.txt
    `-- yet another file with spaces.pdf

हो जाता है:

$ tree
.
|-- a_dir
|   `-- file_with_spaces.txt
`-- b_dir
    |-- another_file_with_spaces.txt
    `-- yet_another_file_with_spaces.pdf

9
यदि foo barएक फ़ाइल को कॉल foo_barकिया जाता है और उसी निर्देशिका में एक अन्य फ़ाइल कहा जाता है तो आप क्या करना चाहते हैं ?
मार्क बायर्स

अच्छा प्रश्न। मैं मौजूदा फ़ाइलों को अधिलेखित करना या कोई डेटा खोना नहीं चाहूंगा। इसे अपरिवर्तित छोड़ देना चाहिए .. आदर्श रूप से एक चेतावनी छापना लेकिन वह शायद बहुत अधिक पूछ रहा है।
आर्मंडिनो

जवाबों:


311

उपयोग rename(उर्फ prename) जो एक पर्ल स्क्रिप्ट है जो आपके सिस्टम पर पहले से हो सकती है। इसे दो चरणों में करें:

find -name "* *" -type d | rename 's/ /_/g'    # do the directories first
find -name "* *" -type f | rename 's/ /_/g'

जुरगेन के उत्तर के आधार पर "रिविजन 1.5 1998/12/18 16:16:31 rmb1" /usr/bin/rename(एक पर्ल स्क्रिप्ट) के संस्करण का उपयोग करके एक ही बाउंड में फ़ाइलों और निर्देशिकाओं की कई परतों को संभालने में सक्षम :

find /tmp/ -depth -name "* *" -execdir rename 's/ /_/g' "{}" \;

5
दो चरणों की आवश्यकता नहीं: गहराई-पहली खोज का उपयोग करें: dir
-depth खोजें

3
ओह, मैं सिर्फ पढ़ा है renameमैनपेज (मैं उपकरण नहीं पता था) और मुझे लगता है कि आप को बदलने के द्वारा अपने कोड का अनुकूलन कर सकते s/ /_/gकरने के लिए y/ /_/;-)
हैकर - माइकल Krelin

1
बेशक आप इसे से एक प्रदर्शन को बढ़ावा देने के लिए नहीं जा रहे हैं। यह सही उपकरण का उपयोग करने के बारे में अधिक है। और यह पूरा प्रश्न कम या ज्यादा सूक्ष्म अनुकूलन के बारे में है। क्या यह मज़ेदार नहीं है? ;-)
माइकल क्रेलिन - हैकर

14
अगर आप इसे OS X पर चला रहे हैं, तो आपको brew install rename
loeschg

7
यह सेंटोस 7 पर काम नहीं करता है, क्योंकि नाम बदलने की कमान पूरी तरह से अलग है (यह एक द्विआधारी है, न कि एक पर्ल स्क्रिप्ट), और यह स्टड से डेटा स्वीकार नहीं करता है।
CpnCrunch

357

मैं उपयोग करता हूं:

for f in *\ *; do mv "$f" "${f// /_}"; done

हालांकि यह पुनरावर्ती नहीं है, यह काफी तेज और सरल है। मुझे यकीन है कि कोई व्यक्ति इसे पुनरावर्ती होने के लिए अद्यतन कर सकता है।

${f// /_}भाग की आपूर्ति की तार के साथ एक पैरामीटर के अंतर्गत पैटर्न को बदलने के लिए पार्टी के पैरामीटर विस्तार प्रकिया का उपयोग करता। प्रासंगिक वाक्यविन्यास है ${parameter/pattern/string}। देखें: https://www.gnu.org/software/bash/manual/html_node/Shell-Parameter-Expansion.html या http://wiki.bash-hackers.org/syntax/pe


9
सरल और मैक में काम करते हैं। (मैक rename
doesnt

6
जबरदस्त जवाब। मैं for d in *\ *; do mv "$d" "${d// /}"; doneस्कोर के तहत गैर इस्तेमाल किया ।
यूं ली

1
'खोज -नाम' के उत्तर के विपरीत, यह एक मेरे ओएस एक्स पर काम करता है! धन्यवाद महोदय!
जूलियो फर्मन

1
संदर्भ के लिए, यह आसानी से उपयोग करने के लिए बैश में पुनरावर्ती बन सकता है shopt -s globstarऔर for f in **/*\ *; do ...globstarजबकि विकल्प, पार्टी के लिए आंतरिक है renameआदेश एक आम लिनक्स उपकरण और नहीं बैश का हिस्सा है।
घट्टी

2
${f// /_}एक है बैश चर विस्तार के लिए खोज और की जगह । - प्रत्येक फ़ाइल के लिए लूप fसे वह चर forहै जिसमें एक स्थान होता है। - पहले का //अर्थ है "सभी को बदलें" (पहली घटना पर रोकें नहीं)। - फिर `/ _` का अर्थ है" अंतरिक्ष को अंडरस्कोर के साथ बदलें "
एर

101
find . -depth -name '* *' \
| while IFS= read -r f ; do mv -i "$f" "$(dirname "$f")/$(basename "$f"|tr ' ' _)" ; done

यह पहली बार में प्राप्त करने में विफल रहा, क्योंकि मैंने निर्देशिकाओं के बारे में नहीं सोचा था।


1
एक जादू की तरह काम करता है। धन्यवाद माइकल।
आर्मंडिनो

डेनिस, अच्छा कैच, आसानी से IFS=''सामने रख कर तय किया read। इसके अलावा, अन्य टिप्पणियों द्वारा मैं जो बता सकता हूं, उसके लिए विकल्प के sortपक्ष में कदम बढ़ाया जा सकता -depthहै find
माइकल क्रेलिन -

1
यदि फ़ाइलनाम में कोई \ (बैकस्लैश) सम्‍मिलित नहीं है, तो कोई काम नहीं करता है । -rपढ़ने के लिए एक विकल्प जोड़कर तय किया जा सकता है ।
jfg956

8
आपके समाधान की प्रतिलिपि बनाने और उसका उपयोग करने के लिए इस पृष्ठ पर जाने के लिए यह ५० वीं बार होना चाहिए। आपका बहुत-बहुत धन्यवाद । मैं आपका जवाब पसंद करता हूं, क्योंकि मैं मैक पर हूं और renameडेनिस द्वारा सुझाई गई कमांड नहीं है ।
एलेक्स कॉन्सटेंटिन 20

@AlexConstantin, नहीं macportsहै rename? मैंने कभी यह जानने की जहमत नहीं उठाई क्योंकि मुझे नहीं लगता कि कार्य उपयोगिता को सही ठहराता है। और यदि आपके पास नहीं है macports, तो आपको उन्हें स्थापित करने पर विचार करना चाहिए;)
माइकल क्रेलिन - हैकर

30

आप detoxडौग हार्पल द्वारा उपयोग कर सकते हैं

detox -r <folder>

12

एक खोज / नाम बदलें समाधान। नाम उपयोग -लिनेक्स का हिस्सा है।

आपको पहले गहराई में उतरने की आवश्यकता है, क्योंकि एक व्हाट्सएप फ़ाइलनाम एक व्हाट्सएप निर्देशिका का हिस्सा हो सकता है:

find /tmp/ -depth -name "* *" -execdir rename " " "_" "{}" ";"

जब मैं तुम्हारी चलती हूं तो मुझे बिल्कुल भी बदलाव नहीं आता है।
अगली सूचना तक रोक दिया गया।

उपयोग-लिनेक्स सेटअप की जाँच करें: $ नाम बदलें -version नाम (उपयोग-
लिनेक्स

ग्रेपिंग / usr / bin / rename (एक पर्ल स्क्रिप्ट) से पता चलता है "संशोधन 1.5 1998/12/18 16:16:31 rmb1"
अगली सूचना तक रोका गया।

हम्म ... तुम्हारा उपयोग-लिनेक्स बाइनरी कहाँ चला गया है? इस फ़ाइल पथ का उपयोग- linux के स्वामित्व में होना चाहिए। आप हमें ग्नू-लिनक्स सिस्टम नहीं देते?
जुरगेन होटेलज़ेल

1
जो केवल मेरे रन में एक स्थान को बदलता है , इसलिए "पर्वत पर आग बताएं" "पहाड़ पर आग लगने वाली" हो जाती है।
ब्रुकर

6

बैश 4.0

#!/bin/bash
shopt -s globstar
for file in **/*\ *
do 
    mv "$file" "${file// /_}"       
done

ऐसा लगता है कि यदि कोई फ़ाइल या निर्देशिका नाम में कोई स्थान नहीं है, तो यह अपने आप ही एक mv कर देगा (mv: a' to a subdirectory of itself, a / a को स्थानांतरित नहीं कर सकता )
armandino

कोई बात नहीं। केवल त्रुटि संदेश को रीडायरेक्ट करके हटा दें /dev/null
भूतडॉग Apr४

ghostdog, mvकेवल पाँच फ़ाइलों का नाम बदलने के लिए पचपन हज़ारों बार, ओवरहेड का एक सा हो सकता है, भले ही आप संदेशों के साथ उपयोगकर्ता को बाढ़ न दें।
माइकल क्रेलिन -

krelin, यहां तक ​​कि उन 55000 फाइलों के माध्यम से जाना जाएगा, जिनका आपने उल्लेख किया था, जिन्हें रिक्त स्थान के साथ खोजा गया था और फिर नाम बदलें। पीछे के अंत में, यह अभी भी सभी के माध्यम से जा रहा है। यदि आप चाहते हैं, तो नाम बदलने से पहले रिक्त स्थान की प्रारंभिक जांच करेंगे।
घोस्टडॉग ghost४

मैं एमवीए स्पॉनिंग के बारे में बात कर रहा था, इससे नहीं गुजर रहा था। नहीं चाहेंगे for file in *' '*या कुछ इस तरह के एक बेहतर काम कर?
माइकल क्रेलिन -

6

आप इसका उपयोग कर सकते हैं:

    find . -name '* *' | while read fname 

do
        new_fname=`echo $fname | tr " " "_"`

        if [ -e $new_fname ]
        then
                echo "File $new_fname already exists. Not replacing $fname"
        else
                echo "Creating new file $new_fname to replace $fname"
                mv "$fname" $new_fname
        fi
done

3

नादिम के जवाबों का पुनरावर्ती संस्करण।

find . -name "* *" | awk '{ print length, $0 }' | sort -nr -s | cut -d" " -f2- | while read f; do base=$(basename "$f"); newbase="${base// /_}"; mv "$(dirname "$f")/$(basename "$f")" "$(dirname "$f")/$newbase"; done

2

यहाँ (काफी वर्बोज़) खोज -सेक्स समाधान है जो लिखते हैं "फ़ाइल पहले से मौजूद है" स्टेडर को चेतावनी:

function trspace() {
   declare dir name bname dname newname replace_char
   [ $# -lt 1 -o $# -gt 2 ] && { echo "usage: trspace dir char"; return 1; }
   dir="${1}"
   replace_char="${2:-_}"
   find "${dir}" -xdev -depth -name $'*[ \t\r\n\v\f]*' -exec bash -c '
      for ((i=1; i<=$#; i++)); do
         name="${@:i:1}"
         dname="${name%/*}"
         bname="${name##*/}"
         newname="${dname}/${bname//[[:space:]]/${0}}"
         if [[ -e "${newname}" ]]; then
            echo "Warning: file already exists: ${newname}" 1>&2
         else
            mv "${name}" "${newname}"
         fi
      done
  ' "${replace_char}" '{}' +
}

trspace rootdir _

2

यह एक छोटा सा अधिक करता है। मैं इसका उपयोग अपने डाउनलोड किए गए टोरेंट (कोई विशेष वर्ण (गैर-एएससीआईआई), रिक्त स्थान, एकाधिक डॉट्स आदि) का नाम बदलने के लिए नहीं करता हूं।

#!/usr/bin/perl

&rena(`find . -type d`);
&rena(`find . -type f`);

sub rena
{
    ($elems)=@_;
    @t=split /\n/,$elems;

    for $e (@t)
    {
    $_=$e;
    # remove ./ of find
    s/^\.\///;
    # non ascii transliterate
    tr [\200-\377][_];
    tr [\000-\40][_];
    # special characters we do not want in paths
    s/[ \-\,\;\?\+\'\"\!\[\]\(\)\@\#]/_/g;
    # multiple dots except for extension
    while (/\..*\./)
    {
        s/\./_/;
    }
    # only one _ consecutive
    s/_+/_/g;
    next if ($_ eq $e ) or ("./$_" eq $e);
    print "$e -> $_\n";
    rename ($e,$_);
    }
}

1

मैंने इस स्क्रिप्ट के आसपास पाया, यह दिलचस्प हो सकता है :)

 IFS=$'\n';for f in `find .`; do file=$(echo $f | tr [:blank:] '_'); [ -e $f ] && [ ! -e $file ] && mv "$f" $file;done;unset IFS

उनके नाम पर नई सुर्खियों वाली फाइलों पर फेल है।
घट्टी


1

MacOS का उपयोग करके इससे जूझने वालों के लिए, पहले सभी उपकरणों को स्थापित करें:

 brew install tree findutils rename

फिर नाम बदलने के लिए, खोज के रूप में GNU खोज (gfind) के लिए एक उपनाम बनाएं। इसके बाद @Michel Krelin का कोड चलाएँ:

alias find=gfind 
find . -depth -name '* *' \
| while IFS= read -r f ; do mv -i "$f" "$(dirname "$f")/$(basename "$f"|tr ' ' _)" ; done   

0

यह केवल वर्तमान निर्देशिका के अंदर फाइलें ढूंढता है और उनका नाम बदल देता है । मेरे पास यह अलियास है।

find ./ -name "* *" -type f -d 1 | perl -ple '$file = $_; $file =~ s/\s+/_/g; rename($_, $file);


0

मैं सिर्फ अपने उद्देश्य से एक बनाता हूं। आप इसे संदर्भ के रूप में उपयोग कर सकते हैं।

#!/bin/bash
cd /vzwhome/c0cheh1/dev_source/UB_14_8
for file in *
do
    echo $file
    cd "/vzwhome/c0cheh1/dev_source/UB_14_8/$file/Configuration/$file"
    echo "==> `pwd`"
    for subfile in *\ *; do [ -d "$subfile" ] && ( mv "$subfile" "$(echo $subfile | sed -e 's/ /_/g')" ); done
    ls
    cd /vzwhome/c0cheh1/dev_source/UB_14_8
done


0

समस्या का मेरा समाधान एक बैश स्क्रिप्ट है:

#!/bin/bash
directory=$1
cd "$directory"
while [ "$(find ./ -regex '.* .*' | wc -l)" -gt 0 ];
do filename="$(find ./ -regex '.* .*' | head -n 1)"
mv "$filename" "$(echo "$filename" | sed 's|'" "'|_|g')"
done

बस निर्देशिका नाम डालें, जिस पर आप स्क्रिप्ट निष्पादित करने के बाद एक तर्क के रूप में स्क्रिप्ट को लागू करना चाहते हैं।


0

MacOS में

चुने हुए उत्तर की तरह।

brew install rename

# 
cd <your dir>
find . -name "* *" -type d | rename 's/ /_/g'    # do the directories first
find . -name "* *" -type f | rename 's/ /_/g'
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.