मैं कमांड लाइन से पुनरावर्ती रूप से एकाधिक फ़ाइलों के विस्तार को कैसे बदलूं?


73

मेरे पास .abcविस्तार के साथ कई फाइलें हैं और उन्हें बदलना चाहते हैं कि .edefg
कमांड लाइन से यह कैसे करें?

मेरे पास कई उप-फ़ोल्डर्स के साथ एक रूट फ़ोल्डर है, इसलिए समाधान को पुनरावर्ती रूप से काम करना चाहिए।


जवाबों:


85

एक पोर्टेबल तरीका (जो किसी भी POSIX आज्ञाकारी प्रणाली पर काम करेगा):

find /the/path -depth -name "*.abc" -exec sh -c 'mv "$1" "${1%.abc}.edefg"' _ {} \;

Bash4 में, आप पुनरावर्ती ग्लब्स (**) प्राप्त करने के लिए ग्लोबस्टार का उपयोग कर सकते हैं:

shopt -s globstar
for file in /the/path/**/*.abc; do
  mv "$file" "${file%.abc}.edefg"
done

renameउबंटू में (पर्ल) कमांड पर्ल रेगुलर एक्सप्रेशन सिंटैक्स का उपयोग करके फ़ाइलों का नाम बदल सकती है, जिसे आप ग्लोबस्टार या के साथ जोड़ सकते हैं find:

# Using globstar
shopt -s globstar
files=(/the/path/**/*.abc)  

# Best to process the files in chunks to avoid exceeding the maximum argument 
# length. 100 at a time is probably good enough. 
# See http://mywiki.wooledge.org/BashFAQ/095
for ((i = 0; i < ${#files[@]}; i += 100)); do
  rename 's/\.abc$/.edefg/' "${files[@]:i:100}"
done

# Using find:
find /the/path -depth -name "*.abc" -exec rename 's/\.abc$/.edefg/' {} +

इसके अलावा http://mywiki.wooledge.org/BashFAQ/030 देखें


पहले वाला बस पुराने एक पर नए विस्तार को जोड़ता है, यह प्रतिस्थापित नहीं करता ...
user2757729

3
@ user2757729, यह इसे प्रतिस्थापित करता है। अंत में बिना सिवाय "${1%.abc}"मूल्य के विस्तार । शेल स्ट्रिंग जोड़तोड़ पर अधिक के लिए faq 100 देखें । $1.abc
जिरह

मैं इसे एक ~ 70k फ़ाइलों की फ़ाइल संरचना पर चलाता था ... कम से कम मेरे शेल पर यह निश्चित रूप से इसे प्रतिस्थापित नहीं करता था।
user2757729

1
@ user2757729 आपने शायद "abc" छोड़ दिया${1%.abc}...
kvnn

1
यदि कोई अन्य व्यक्ति यह सोच रहा है कि पहले कमांड में अंडरस्कोर क्या कर रहा है, तो इसकी आवश्यकता है क्योंकि sh -c पहले तर्क के साथ $ 0 को सौंपा गया है और किसी भी शेष तर्क को स्थितीय मापदंडों को सौंपा गया है । तो _यह एक डमी तर्क है, और '{}' पहला पद है sh -c
हेलोबेब्लन

48

यह आवश्यक कार्य करेगा यदि सभी फाइलें एक ही फ़ोल्डर में हैं

rename 's/.abc$/.edefg/' *.abc

फ़ाइलों का नाम बदलने के लिए इसे पुन: उपयोग करें:

find /path/to/root/folder -type f -name '*.abc' -print0 | xargs -0 rename 's/.abc$/.edefg/'

8
या rename 's/.abc$/.edefg/' /path/to/root/folder/**/*.abcबैश के आधुनिक संस्करण में।
एडम ब्रीटेक

मुझे कैसे उपयोग करने के लिए पर एक टिप देने के लिए महान धन्यवाद एडम। * फ़ोल्डर में। पुनरावर्ती!
राफेल सिलेक

महान टिप, धन्यवाद! मुझे रेगेक्स के सिंटैक्स के छोटे टुकड़े के बारे में अधिक दस्तावेज कहां मिल सकते हैं? जैसे कि sशुरुआत में क्या है, और मैं अन्य विकल्पों का क्या उपयोग कर सकता हूं। धन्यवाद !
Anto

@AdamByrtek मैं सिर्फ यूटोपिक पर आपके सुझाव के साथ विफल रहा। ('ऐसी कोई फाइलें नहीं' या कुछ ऐसी।)
जोनाथन वाई।

14

पुनरावर्ती नाम बदलने के साथ एक समस्या यह है कि आप फ़ाइलों का पता लगाने के लिए जो भी विधि का उपयोग करते हैं, वह renameकेवल फ़ाइल नाम के लिए नहीं बल्कि पूरे रास्ते से गुजरती है । यह नेस्टेड फ़ोल्डर्स में जटिल नाम बदलने के लिए कठिन बनाता है।

मैं उपयोग findकी -execdirइस समस्या को हल करने के लिए कार्रवाई की। यदि आप -execdirइसके बजाय उपयोग करते हैं -exec, तो निर्दिष्ट कमांड उपनिर्देशिका से मेल खाते फ़ाइल से चलाया जाता है। इसलिए, पूरे रास्ते को पारित करने के बजाय rename, यह केवल गुजरता है ./filename। इससे रेगेक्स लिखना बहुत आसान हो जाता है।

find /the/path -type f \
               -name '*.abc' \
               -execdir rename 's/\.\/(.+)\.abc$/version1_$1.abc/' '{}' \;

विस्तार से:

  • -type f इसका मतलब केवल फाइलों को देखना है, निर्देशिकाओं को नहीं
  • -name '*.abc' का मतलब केवल उन फिल्नामों से है जो अंत में .abc से मेल खाते हैं
  • '{}'वह प्लेसहोल्डर है जो उस जगह को चिह्नित करता है जहां -execdirपाया गया पथ सम्मिलित होगा। सिंगल-कोट्स की आवश्यकता होती है, यह रिक्त स्थान और शेल वर्णों के साथ फ़ाइल नामों को संभालने की अनुमति देता है।
  • बैकस्लैश के बाद -typeऔर -nameबैश लाइन-निरंतरता चरित्र हैं। मैं उन्हें इस उदाहरण को और अधिक पठनीय बनाने के लिए उपयोग करता हूं, लेकिन यदि आप अपनी आज्ञा को एक पंक्ति में रखते हैं, तो उनकी आवश्यकता नहीं है।
  • हालाँकि, -execdirपंक्ति के अंत में बैकस्लैश आवश्यक है। यह अर्धविराम से बचने के लिए है, जो इसके द्वारा संचालित कमांड को समाप्त करता है -execdir। आनंद!

रेगेक्स की व्याख्या:

  • s/ रेगेक्स की शुरुआत
  • \.\/अग्रणी से मिलाएं। /। -से बचने के लिए उपयोग करें। और / मेटाचैटर्स (ध्यान दें: यह हिस्सा आपके संस्करण के आधार पर भिन्न होता है find। उपयोगकर्ता @apollo की टिप्पणी देखें)
  • (.+)फ़ाइल नाम से मिलान करें। कोष्ठक बाद में उपयोग के लिए मैच पर कब्जा कर लेते हैं
  • \.abc डॉट से बचो, एबीसी से मेल करो
  • $ स्ट्रिंग के अंत में मैच को एंकर करें

  • / रेगेक्स के "मैच" भाग के अंत को चिह्नित करता है, और "बदलें" भाग की शुरुआत

  • version1_ इस पाठ को हर फ़ाइल नाम में जोड़ें

  • $1मौजूदा फ़ाइल नाम का संदर्भ देता है, क्योंकि हमने इसे कोष्ठक के साथ कैप्चर किया है। यदि आप "मैच" भाग में कोष्ठक के कई सेटों का उपयोग करते हैं, तो आप $ 2, $ 3, आदि का उपयोग करके उन्हें यहां संदर्भित कर सकते हैं।
  • .abcनया फ़ाइल नाम .abc में समाप्त होगा। "बदलें" अनुभाग में यहां डॉट मेटाचैकर से बचने की आवश्यकता नहीं है
  • / रेगेक्स का अंत

इससे पहले

tree --charset=ascii

|-- a_file.abc
|-- Another.abc
|-- Not_this.def
`-- dir1
    `-- nested_file.abc

उपरांत

tree --charset=ascii

|-- version1_a_file.abc
|-- version1_Another.abc
|-- Not_this.def
`-- dir1
    `-- version1_nested_file.abc

संकेत: rename's -n विकल्प उपयोगी है। यह एक सूखा रन करता है और आपको दिखाता है कि यह किस नाम से बदल जाएगा, लेकिन कोई बदलाव नहीं करता है।


विवरण स्पष्टीकरण के लिए धन्यवाद, लेकिन अजीब बात है, जब मैं यह कोशिश करता हूं, तो --execdirअग्रणी में पास नहीं हुआ ./ताकि \.\/रेगेक्स में भाग छोड़ा जा सके। ऐसा इसलिए हो सकता है क्योंकि मैं OSX पर हूं ubuntu नहीं
अपोलो

5

एक और पोर्टेबल तरीका:

find /the/path -depth -type f -name "*.abc" -exec sh -c 'mv -- "$1" "$(dirname "$1")/$(basename "$1" .abc).edefg"' _ '{}' \;

4
उबंटू पूछने के लिए आपका स्वागत है! हालांकि यह एक मूल्यवान उत्तर है, मैं इसे (यह संपादन करके) यह बताने की सलाह देता हूं कि यह कैसे और क्यों काम करता है।
एलियाह कगन

3
# Rename all *.txt to *.text
for f in *.txt; do 
mv -- "$f" "${f%.txt}.text"
done

यह भी देखें कि आपको पार्स क्यों नहीं करना चाहिए ls

संपादित करें: यदि आपको बेसनेम का उपयोग करना है तो आपका सिंटैक्स होगा:

for f in *.txt; do
mv -- "$f" "$(basename "$f" .txt).text"
done

https://unix.stackexchange.com/questions/19654/changing-extension-to-multiple-files


0

यह वही है जो मैंने किया और जैसा मैंने चाहा वैसे ही बहुत काम किया। मैंने mvकमांड का उपयोग किया । मेरे पास कई .3gpफाइलें थीं और मैं उन सभी का नाम बदलना चाहता था.mp4

यहाँ इसके लिए एक छोटा oneliner है:

for i in *.3gp; do mv -- "$i" "ren-$i.mp4"; done

जो केवल वर्तमान निर्देशिका के माध्यम से स्कैन करता है, सभी .3gp फ़ाइलों को चुनता है, फिर नाम बदलकर (mv का उपयोग करके) करता है ren-name_of_file.mp4


इसका नाम बदल file.3gpदिया जाएगा file.3gp.mp4, जो कि ज्यादातर लोग नहीं चाहते हैं।
मुरु

@ मुरु लेकिन सिद्धांत अभी भी मौजूद है। बस किसी भी एक्सटेंशन का चयन करें और फिर उनका नाम बदलने के लिए गंतव्य एक्सटेंशन निर्दिष्ट करें। .3gpया .mp4यहाँ सिर्फ समझाने के उद्देश्य से कर रहे थे।
खोही

वाक्य रचना बेहतर, एक-लाइनर और समझने में आसान है। हालांकि, मैं basename "$i" .mp4"ren- $ i.mp4" के बजाय पिछले एक्सटेंशन को हटाने के लिए उपयोग करूंगा।
ताओपीआर

सच। अच्छी बात।
खोही

0

मुझे इसे हासिल करने का एक आसान तरीका मिला। Jpg से पीडीएफ में कई फाइलों के एक्सटेंशन बदलने के लिए, उपयोग करें:

for file in /path/to; do mv $file $(basename -s jpg $file)pdf ; done


0

फ़ाइलों और निर्देशिकाओं का नाम बदलें find -execdir | rename

यदि आप केवल एक प्रत्यय के साथ फाइल और निर्देशिका दोनों का नाम नहीं बदलने जा रहे हैं, तो यह एक अच्छा पैटर्न है:

PATH="$(echo "$PATH" | sed -E 's/(^|:)[^\/][^:]*//g')" \
  find . -depth -execdir rename 's/findme/replaceme/' '{}' \;

इसके विपरीत, कमांड निष्पादित करने से पहले कमाल का -execdirविकल्प cdडायरेक्टरी में होता है ।rename-exec

-depth यह सुनिश्चित करना कि बच्चों का नामकरण पहले माता-पिता और फिर माता-पिता पर होता है, ताकि लापता माता-पिता की अनुपस्थिति के साथ संभावित समस्याओं को रोका जा सके।

-execdir आवश्यक है क्योंकि नाम गैर-बेसन इनपुट पथों के साथ अच्छी तरह से नहीं चलता है, उदाहरण के लिए निम्न विफल रहता है:

rename 's/findme/replaceme/g' acc/acc

PATHहैकिंग की आवश्यकता है क्योंकि है -execdirएक बहुत कष्टप्रद दोष यह है: findअत्यंत स्वच्छंद जाता है और साथ कुछ भी करने से मना -execdirकरता है, तो आप अपने किसी भी संबंधित पथ है PATHवातावरण चर, जैसे ./node_modules/.bin, साथ में नाकाम रहने के:

खोज: सापेक्ष पथ './node_modules/.bin' को PATH पर्यावरण चर में शामिल किया गया है, जो खोज की -execdir कार्रवाई के साथ संयोजन में असुरक्षित है। कृपया उस प्रविष्टि को $ PATH से हटा दें

यह भी देखें: '-execdir' कार्रवाई का उपयोग उस निर्देशिका के लिए असुरक्षित क्यों है जो PATH में है?

-execdirएक GNU POSIX के लिए एक्सटेंशन ढूंढता हैrenameपर्ल आधारित है और renameपैकेज से आता है । उबंटू 18.10 में परीक्षण किया गया।

नाम बदलें समाधान देखें

यदि आपके इनपुट पथ से नहीं आते हैं find, या यदि आपके पास सापेक्ष पथ झुंझलाहट है, तो हम कुछ पर्ल लुकहेड का उपयोग सुरक्षित रूप से निर्देशिकाओं का नाम बदलने के लिए कर सकते हैं:

git ls-files | sort -r | xargs rename 's/findme(?!.*\/)\/?$/replaceme/g' '{}'

मैं के लिए एक सुविधाजनक अनुरूप नहीं मिला है -execdirसाथ xargs: https://superuser.com/questions/893890/xargs-change-working-directory-to-file-path-before-executing/915686

यह sort -rसुनिश्चित करने के लिए आवश्यक है कि फाइलें उनके संबंधित निर्देशिकाओं के बाद आती हैं, क्योंकि लंबे समय तक पथ एक ही उपसर्ग के साथ छोटे के बाद आते हैं।

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