बड़े पैमाने पर फ़ाइल का नाम बदलने के लिए sed का उपयोग करना


89

उद्देश्य

इन फ़ाइल नाम को बदलें:

  • F00001-0708-आरजी biasliuyda
  • F00001-0708-CS-akgdlaul
  • F00001-0708-VF-hioulgigl

इन फ़ाइलनामों के लिए:

  • F0001-0708-आरजी biasliuyda
  • F0001-0708-CS-akgdlaul
  • F0001-0708-VF-hioulgigl

शेल कोड

परीक्षा करना:

ls F00001-0708-*|sed 's/\(.\).\(.*\)/mv & \1\2/'

निष्पादित करना:

ls F00001-0708-*|sed 's/\(.\).\(.*\)/mv & \1\2/' | sh

मेरा प्रश्न

मुझे sed कोड समझ में नहीं आता है। मैं समझता हूं कि प्रतिस्थापन की कमान क्या है

$ sed 's/something/mv'

माध्यम। और मैं कुछ हद तक नियमित अभिव्यक्ति को समझता हूं। लेकिन मुझे समझ नहीं आ रहा है कि यहाँ क्या हो रहा है:

\(.\).\(.*\)

या इधर:

& \1\2/

मेरे लिए, पूर्व जैसा दिखता है, इसका मतलब है: "एक एकल वर्ण, उसके बाद एक एकल वर्ण, उसके बाद एक एकल वर्ण का कोई भी लंबाई अनुक्रम" - लेकिन निश्चित रूप से इसके अलावा भी बहुत कुछ है। जहाँ तक बाद वाला हिस्सा है:

& \1\2/

मुझे पता नहीं है।


जवाबों:


152

सबसे पहले, मुझे यह कहना चाहिए कि ऐसा करने का सबसे आसान तरीका है कि आप प्रिनेम या नाम बदलें कमांड का उपयोग करें।

उबंटू पर, OSX (Homebrew पैकेज rename, MacPorts पैकेज p5-file-rename), या अन्य सिस्टम पर्ल नाम (नाम):

rename s/0000/000/ F0000*

या उपयोग-लिनेक्स-एनजी से नाम बदलने वाले सिस्टम पर, जैसे कि RHEL:

rename 0000 000 F0000*

समतुल्य सीड कमांड की तुलना में यह बहुत अधिक समझने योग्य है।

लेकिन जैसा कि sed कमांड को समझने के लिए, sed मैनपेज मददगार है। यदि आप मैन सेड चलाते हैं और & / (सर्च करने के लिए / कमांड का उपयोग करके) खोजते हैं, तो आप पाएंगे कि यह s / foo / bar / प्रतिस्थापन में एक विशेष चरित्र है।

  s/regexp/replacement/
         Attempt  to match regexp against the pattern space.  If success‐
         ful,  replace  that  portion  matched  with  replacement.    The
         replacement may contain the special character & to refer to that
         portion of the pattern space  which  matched,  and  the  special
         escapes  \1  through  \9  to refer to the corresponding matching
         sub-expressions in the regexp.

इसलिए, \(.\)पहले चरित्र से मेल खाता है, जिसे संदर्भित किया जा सकता है \1। फिर .अगले चरित्र से मेल खाता है, जो हमेशा 0. है। फिर \(.*\)शेष फ़ाइल नाम से मेल खाता है, जिसे संदर्भित किया जा सकता है \2

प्रतिस्थापन स्ट्रिंग यह सब &(मूल फ़ाइल नाम) का उपयोग करके एक साथ रखती है और \1\2जो कि 2 अक्षर को छोड़कर फ़ाइल नाम का प्रत्येक भाग है, जो कि 0 था।

यह ऐसा करने के लिए एक सुंदर गूढ़ तरीका है, IMHO। यदि किसी कारण से नाम बदलने की आज्ञा उपलब्ध नहीं थी और आप नाम बदलने के लिए sed का उपयोग करना चाहते थे (या शायद आप नाम बदलने के लिए कुछ जटिल कर रहे थे?), तो आपके regex में अधिक स्पष्ट होने से यह अधिक पठनीय बन जाएगा। शायद कुछ इस तरह:

ls F00001-0708-*|sed 's/F0000\(.*\)/mv & F000\1/' | sh

यह देखने में सक्षम है कि वास्तव में एस / खोज / प्रतिस्थापन में क्या बदल रहा है / यह बहुत अधिक पठनीय बनाता है। यदि आप गलती से इसे दो बार या कुछ और चलाते हैं, तो यह आपके फ़ाइल नाम से बाहर चूसने वाले पात्रों को नहीं रखेगा।


1
मेरे RHEL सर्वर पर, नाम वाक्य रचना "0000 000 F0000 * का नाम बदलें"
डेविड लेबॉयर

1
यह सबसे अधिक संभावना है कि renameस्वयं एक "बदला हुआ" लिंक है। अर्थात " से " का नाम बदलrename दिया गया है । उदाहरण के लिए, उबंटू में: आउटपुट ... डेविड द्वारा उल्लिखित एक पूरी तरह से एक अलग कार्यक्रम है। prenamereadlink -f $(which rename)/usr/bin/prenamerename
पीटर।

1
अच्छी बात, पीटर। मैंने नाम बदलने की उपयोगिताओं दोनों का जवाब देने के लिए अद्यतन किया है।
एडवर्ड एंडरसन

3
इसे डीबग करने के लिए, अंत में पाइप को श में निकालें। कमांड स्क्रीन पर गूंजेंगे।
बेन मैथ्यूज

1
क्या आप सुनिश्चित हैं कि रैंडम डेटा पाइप के माध्यम से देना एक अच्छी सलाह है sh? यह संभावित रूप से खतरनाक है क्योंकि मनमाना कोड निष्पादित किया जा सकता है (आप डेटा को कोड के रूप में मान रहे हैं)।
गनीउरफ_गनीउरफ

46

आपके पास आपकी व्याख्या है, अब आप केवल शेल का उपयोग कर सकते हैं, बाहरी कमांड की आवश्यकता नहीं है

for file in F0000*
do
    echo mv "$file" "${file/#F0000/F000}"
    # ${file/#F0000/F000} means replace the pattern that starts at beginning of string
done

1
अच्छा है, लेकिन आप कोष्ठक के साथ संदर्भ नहीं कर सकते।
लियोनिडस त्समप्रोस

28

मैंने sedकुछ साल पहले बैच का नाम बदलने के उदाहरण पर एक छोटी सी पोस्ट लिखी थी:

http://www.guyrutenberg.com/2009/01/12/batch-renaming-using-sed/

उदाहरण के लिए:

for i in *; do
  mv "$i" "`echo $i | sed "s/regex/replace_text/"`";
done

यदि रेगेक्स में समूह (जैसे \(subregex\) हैं तो आप उन्हें प्रतिस्थापन पाठ में उपयोग कर सकते हैं \1\, \2आदि।


ध्यान दें कि लिंक-केवल उत्तर हतोत्साहित किए जाते हैं (लिंक समय के साथ बासी हो जाते हैं)। कृपया अपने उत्तर को संपादित करने और यहाँ एक सारांश लिखने पर विचार करें।
क्लियोपेट्रा

यह कुशल नहीं है, लेकिन युगल सौ फाइलों के लिए काम करता है। Upvoted।
वरुण चांडक

23

सबसे आसान तरीका होगा:

for i in F00001*; do mv "$i" "${i/F00001/F0001}"; done

या, आंशिक रूप से,

for i in F00001*; do mv "$i" "F0001${i#F00001}"; done

यह F00001फ़ाइल नाम के साथ उपसर्ग को प्रतिस्थापित करता है F0001। यहाँ महेश को श्रेय: http://www.debian-administration.org/articles/150


3
आपको परिवर्तनीय प्रक्षेपों को ठीक से उद्धृत करना चाहिए; mv "$i" "${i/F00001/F0001}"। लेकिन +1
ट्रिपल

7

sedआदेश

s/\(.\).\(.*\)/mv & \1\2/

बदलने का मतलब:

\(.\).\(.*\)

साथ में:

mv & \1\2

एक नियमित sedआदेश की तरह । हालाँकि, कोष्ठक, &और \nमार्कर इसे थोड़ा बदल देते हैं।

खोज स्ट्रिंग मेल खाता है (और पैटर्न 1 के रूप में याद करता है) शुरुआत में एकल चरित्र, उसके बाद एक एकल चरित्र, शेष स्ट्रिंग द्वारा follwed (पैटर्न 2 के रूप में याद किया गया)।

प्रतिस्थापन स्ट्रिंग में, आप प्रतिस्थापन के हिस्से के रूप में उपयोग करने के लिए इन मिलान किए गए पैटर्न का उल्लेख कर सकते हैं। आप पूरे मिलान वाले भाग को भी संदर्भित कर सकते हैं &

तो जो sedआदेश कर रहा है mvवह मूल फ़ाइल (स्रोत के लिए) और चरित्र 1 और 3 के आधार पर एक कमांड बना रहा है , प्रभावी रूप से चरित्र 2 (गंतव्य के लिए) को हटा रहा है। यह आपको निम्न प्रारूप के साथ लाइनों की एक श्रृंखला देगा:

mv F00001-0708-RG-biasliuyda F0001-0708-RG-biasliuyda
mv abcdef acdef

और इसी तरह।


1
यह एक अच्छा स्पष्टीकरण था, लेकिन यह इंगित करने के लिए उपयोगी हो सकता है कि आप अन्य कमांड के साथ sed कमांड का उपयोग कैसे करते हैं, वास्तव में फाइलों का नाम बदल सकते हैं। उदाहरण के लिए:ls | sed "s/\(.\).\(.*\)/mv & \1\2/" | bash
जर्कबेलो

@jcarballo: यह एक शेल के माध्यमls से पार्स , पाइप के माध्यम से sedऔर फिर पाइप के लिए खतरनाक है ! यह जाली फाइलनामों के साथ मनमाने कोड निष्पादन के अधीन है। समस्या यह है कि डेटा को डेटा के रूप में माना जाना चाहिए, और यहां यह आमतौर पर किसी भी सावधानियों के बिना कोड में क्रमबद्ध है। काश paxdiablo इस जवाब को हटा सकता है क्योंकि यह वास्तव में अच्छा अभ्यास नहीं दिखाता है। (मैं इस सवाल पर अड़ गया क्योंकि एक शुरुआत बेतरतीब ढंग से | shएक कमांड के बाद पाई गई जो काम नहीं करती थी और इस सवाल और उत्तरों को देखने के बाद लगा कि यह बेहतर काम करेगा- मैं बुरी तरह से डर गया!) :)
गनीउर_गनीउरफ

3

बैकस्लैश-पारेन सामान का मतलब है, "पैटर्न से मेल खाते समय, यहां से मेल खाने वाले सामान को पकड़ें।" बाद में, प्रतिस्थापन पाठ पक्ष पर, आप उन याद किए गए अंशों को "\ 1" (पहले कोष्ठक ब्लॉक), "\ 2" (दूसरा ब्लॉक), और इसी तरह वापस पा सकते हैं।


1

यदि आप वास्तव में कर रहे हैं तो दूसरा चरित्र हटा रहा है, चाहे जो भी हो, आप यह कर सकते हैं:

s/.//2

लेकिन आपका आदेश एक कमांड का निर्माण कर रहा है mvऔर इसे निष्पादन के लिए शेल में पाइप कर रहा है।

यह आपके संस्करण से अधिक पठनीय नहीं है:

find -type f | sed -n 'h;s/.//4;x;s/^/mv /;G;s/\n/ /g;p' | sh

चौथा चरित्र हटा दिया गया है क्योंकि findप्रत्येक फ़ाइल नाम "/ ./" के साथ चल रहा है।


काश आप इस उत्तर को हटा सकते। हालांकि यह ओपी के बहुत विशिष्ट मामले में शायद अच्छा था, इस तरह के जवाब देखने वाले बहुत से लोग हैं और इसे नहीं समझते हैं, और बेतरतीब ढंग से | shएक कमांड के बाद पाइप करते हैं जो काम नहीं करता है, इस उम्मीद में कि यह काम करेगा बेहतर। यह भयावह है! (और इसके अलावा, यह अच्छा अभ्यास नहीं है)। मुझे आशा है कि आप समझ जाएंगे!
ग्नौरफ_ग्निऑरफ

1

पर्ल नाम का उपयोग करना ( टूलबॉक्स में होना चाहिए ):

rename -n 's/0000/000/' F0000*

-nजब आउटपुट वास्तविक के लिए नाम बदलना अच्छा लगे तो स्विच हटा दें ।

चेतावनी एक ही नाम के साथ अन्य उपकरण हैं जो ऐसा करने में सक्षम हो सकते हैं या नहीं कर सकते हैं, इसलिए सावधान रहें।

util-linuxपैकेज का हिस्सा है, जो नाम बदलें आदेश नहीं होगा।

यदि आप निम्न कमांड चलाते हैं ( GNU)

$ rename

और आप देखते हैं perlexpr, तो यह सही उपकरण लगता है।

यदि नहीं, तो इसे डिफ़ॉल्ट रूप से (आमतौर पर पहले से ही मामला) बनाने Debianऔर व्युत्पन्न करने के लिए जैसे Ubuntu:

$ sudo apt install rename
$ sudo update-alternatives --set rename /usr/bin/file-rename

आर्च्लिनक्स के लिए:

pacman -S perl-rename

रेडहैट-पारिवारिक विकृतियों के लिए:

yum install prename

ईपीईएल भंडार में 'प्रिनाम' पैकेज है ।


जेंटू के लिए:

emerge dev-perl/rename

* बीएसडी के लिए:

pkg install gprename

या p5-File-Rename


मैक उपयोगकर्ताओं के लिए:

brew install rename

यदि आपके पास एक और डिस्ट्रो के साथ यह कमांड नहीं है, तो इसे स्थापित करने या मैन्युअल रूप से करने के लिए अपने पैकेज मैनेजर को खोजें :

cpan -i File::Rename

पुराना स्टैंडअलोन संस्करण यहां पाया जा सकता है


आदमी का नाम


यह उपकरण मूल रूप से लैरी वाल, पर्ल के पिता द्वारा लिखा गया था।


0

कोष्ठक बैकस्लेस्ड संख्याओं द्वारा उपयोग के लिए विशेष तारों को कैप्चर करते हैं।


0
 ls F00001-0708-*|sed 's|^F0000\(.*\)|mv & F000\1|' | bash

भयानक! मनमाने ढंग से कोड निष्पादन के अधीन (शायद प्रश्न के विशिष्ट संदर्भ में नहीं है, लेकिन ऐसे बहुत से लोग हैं जो इस तरह के उत्तर देख रहे हैं और बेतरतीब ढंग से कुछ ऐसा टाइप करने की कोशिश करते हैं जो इसे पसंद करते हैं, और यह खतरनाक डरा रहा है!)। मेरी इच्छा है कि आप इस उत्तर को हटा सकते हैं (इसके अलावा, आपके पास यहाँ पर एक और अच्छा है, जो मैंने उतारा है)।
गनीउर्फ_निगोरफ

0

यहाँ मैं क्या करूँगा:

for file in *.[Jj][Pp][Gg] ;do 
    echo mv -vi \"$file\" `jhead $file|
                           grep Date|
                           cut -b 16-|
                           sed -e 's/:/-/g' -e 's/ /_/g' -e 's/$/.jpg/g'` ;
done

फिर अगर यह ठीक लग रहा है, | shतो अंत में जोड़ें । इसलिए:

for file in *.[Jj][Pp][Gg] ;do 
    echo mv -vi \"$file\" `jhead $file|
                           grep Date|
                           cut -b 16-|
                           sed -e 's/:/-/g' -e 's/ /_/g' -e 's/$/.jpg/g'` ;
done | sh

0

कुछ उदाहरण जो मेरे लिए काम करते हैं:

$ tree -L 1 -F .
.
├── A.Show.2020.1400MB.txt
└── Some Show S01E01 the Loreming.txt

0 directories, 2 files

## remove "1400MB" (I: ignore case) ...

$ for f in *; do mv 2>/dev/null -v "$f" "`echo $f | sed -r 's/.[0-9]{1,}mb//I'`"; done;
renamed 'A.Show.2020.1400MB.txt' -> 'A.Show.2020.txt'

## change "S01E01 the" to "S01E01 The"
## \U& : change (here: regex-selected) text to uppercase;
##       note also: no need here for `\1` in that regex expression

$ for f in *; do mv 2>/dev/null "$f" "`echo $f | sed -r "s/([0-9] [a-z])/\U&/"`"; done

$ tree -L 1 -F .
.
├── A.Show.2020.txt
└── Some Show S01E01 The Loreming.txt

0 directories, 2 files
$ 

-1
for i in *; do mv $i $(echo $i|sed 's/AAA/BBB/'); done

4
एसओ में आपका स्वागत है। कृपया अपने कोड का विवरण जोड़ने पर विचार करें। इसे समझने में अन्य उपयोगकर्ताओं को मदद मिलेगी।
दिग्विजय एस

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