खोज और sed का उपयोग करके फ़ाइलों को पुन: नाम बदलें


85

मैं निर्देशिकाओं के एक समूह के माध्यम से जाना चाहता हूं और सभी फ़ाइलों का नाम बदलना चाहता हूं जो _test.rb में समाप्त होते हैं बजाय _spec.rb में समाप्त होते हैं। यह कुछ ऐसा है जिसे मैंने कभी नहीं सोचा है कि इस तरह से कैसे किया जाए ताकि इस बार मुझे लगा कि मैं इसे निकालने के लिए कुछ प्रयास करूंगा। मैं अब तक कम आया हूं, हालांकि मेरा सबसे अच्छा प्रयास है:

find spec -name "*_test.rb" -exec echo mv {} `echo {} | sed s/test/spec/` \;

NB: निष्पादन के बाद एक अतिरिक्त प्रतिध्वनि होती है ताकि जब मैं इसका परीक्षण कर रहा हूं तो कमांड रन के बजाय मुद्रित हो।

जब मैं इसे प्रत्येक मिलान फ़ाइल नाम के लिए आउटपुट चलाता हूं:

mv original original

अर्थात सेड द्वारा प्रतिस्थापन खो गया है। चाल क्या है?


BTW, मुझे पता है कि एक नाम बदलने की कमान है, लेकिन मैं वास्तव में यह पता लगाना चाहूंगा कि कैसे यह sed का उपयोग करना है ताकि मैं भविष्य में और अधिक शक्तिशाली कमांड कर सकूं।
opsb


जवाबों:


32

ऐसा इसलिए होता है क्योंकि इनपुट के रूप sedमें स्ट्रिंग प्राप्त करता है {}, जैसा कि इसके साथ सत्यापित किया जा सकता है:

find . -exec echo `echo "{}" | sed 's/./foo/g'` \;

जो foofooनिर्देशिका में प्रत्येक फ़ाइल के लिए पुनरावर्ती रूप से प्रिंट करता है। इस व्यवहार का कारण यह है कि पाइप लाइन को एक बार शेल द्वारा निष्पादित किया जाता है, जब यह पूरी कमांड का विस्तार करता है।

sedपाइपलाइन को इस तरह से उद्धृत करने का कोई तरीका नहीं है जो findइसे हर फ़ाइल के लिए निष्पादित करेगा, क्योंकि findशेल के माध्यम से कमांड निष्पादित नहीं करता है और पाइपलाइन या बैकक्वाट्स की कोई धारणा नहीं है। GNU फाइंडटिल्स मैनुअल बताता है कि पाइपलाइन को एक अलग शेल स्क्रिप्ट में डालकर एक समान कार्य कैसे किया जाता है:

#!/bin/sh
echo "$1" | sed 's/_test.rb$/_spec.rb/'

( sh -cएक आदेश में यह सब करने के लिए उपयोग करने के कुछ विकृत तरीके और कुछ टन उद्धरण हो सकते हैं, लेकिन मैं कोशिश करने वाला नहीं हूं।)


27
Sh -c के विकृत उपयोग के बारे में सोच रहे लोगों के लिए यह है: spec -name "* _test.rb" -exec sh -c 'echo mv "$ 1" "$ (echo" $ 1 ") खोजें। sed / test.rb | \ $ / spec.rb /) "'_ {} \;
ओप्सब

1
@ उफ़ क्या बात है? महान समाधान - लेकिन मुझे रामट्टम का जवाब ज्यादा पसंद है :)
iRaS

चीयर्स! मुझे बहुत सिरदर्द से बचाया। पूर्णता के लिए यह है कि मैं इसे एक स्क्रिप्ट में कैसे पाइप करता हूं: खोज। -नाम "फ़ाइल" -exec sh /path/to/script.sh {} \;
स्वेन एम।

128

एक तरह से मूल समस्या के सबसे करीब से हल करने के लिए शायद xargs "आर्ग्स प्रति कमांड लाइन" विकल्प का उपयोग करना होगा:

find . -name "*_test.rb" | sed -e "p;s/test/spec/" | xargs -n2 mv

यह वर्तमान कार्यशील निर्देशिका में फ़ाइलों को पुनरावर्ती रूप से ढूँढता है, मूल फ़ाइल नाम ( p) और फिर संशोधित नाम ( s/test/spec/) को जोड़ता है और इसे सभी mvजोड़े ( xargs -n2) में खिलाता है । खबरदार कि इस मामले में पथ में स्वयं स्ट्रिंग नहीं होना चाहिए test


9
दुर्भाग्य से इसमें सफेद अंतरिक्ष के मुद्दे हैं। इसलिए नाम में रिक्त स्थान वाले फ़ोल्डरों के साथ प्रयोग करने से यह xargs पर टूट जाएगा (क्रिया के साथ -p / इंटरेक्टिव मोड के लिए पुष्टि करें)
cde

1
ठीक वैसा ही मैं देख रहा था। सफेद स्थान के मुद्दे के लिए बहुत बुरा है (मैंने इसे परीक्षण नहीं किया, हालांकि)। लेकिन मेरी मौजूदा जरूरतों के लिए यह सही है। मैं इसे "एक्सआरजी" के पैरामीटर के रूप में "एमवी" के बजाय "इको" के साथ पहले परीक्षण करने का सुझाव देता हूं।
मिशेल डल'गाटा

5
यदि आपको रास्तों में व्हाट्सएप से निपटने की आवश्यकता है और आप GNU sed> = 4.2.2 का उपयोग कर रहे हैं तो आप -zढूँढता है -print0और xargs के साथ विकल्प का उपयोग कर सकते हैं -0:find -name '*._test.rb' -print0 | sed -ze "p;s/test/spec/" | xargs -0 -n2 mv
Evan Purkhiser

सबसे अच्छा उपाय। इतनी तेजी से खोजने के लिए -exec से। धन्यवाद
मिगुएल ए Baldi Hörlle

यह काम नहीं करेगा, अगर testएक पथ में कई फ़ोल्डर हैं । sedकेवल पहले एक का नाम बदलेगा और त्रुटि mvपर कमांड विफल हो जाएगी No such file or directory
केसी

22

आप अन्य तरीकों पर विचार करना चाह सकते हैं

for file in $(find . -name "*_test.rb")
do 
  echo mv $file `echo $file | sed s/_test.rb$/_spec.rb/`
done

यह ऐसा करने का एक अच्छा तरीका है। मैं वास्तव में एक लाइनर को क्रैक करने के लिए देख रहा हूं, हालांकि मेरे ज्ञान को और कुछ से बेहतर बनाने के लिए।
opsb

2
$ में फ़ाइल के लिए (खोजें। -नेमी "* _test.rb"); इको mv $ फाइल करना echo $file | sed s/_test.rb$/_spec.rb/; किया एक लाइनर है, है ना?
ब्रेटिकस

5
यदि आप रिक्त स्थान के साथ फ़ाइल नाम रखते हैं तो यह काम नहीं करेगा। forउन्हें अलग-अलग शब्दों में विभाजित करेगा। आप इसे लूप के लिए निर्देश देकर काम कर सकते हैं, केवल नई सीमा पर विभाजित करने के लिए। उदाहरण के लिए cyberciti.biz/tips/handling-filenames-with-spaces-in-bash.html देखें ।
onitake

मैं @onitake से सहमत हूं, हालांकि मैं -execखोज से विकल्प का उपयोग करना पसंद करूंगा ।
शेलफिश

18

मुझे यह एक छोटा लगता है

find . -name '*_test.rb' -exec bash -c 'echo mv $0 ${0/test.rb/spec.rb}' {} \;

नमस्ते, मुझे लगता है कि ' _test.rb' को ' _test.rb' (एकल उद्धरण का दोहरा भाव) होना चाहिए । क्या मैं पूछ सकता हूं कि आप अंडरस्कोर का उपयोग उस तर्क को धक्का देने के लिए कर रहे हैं जिसे आप $ 1 की स्थिति में लाना चाहते हैं जब यह मुझे लगता है कि यह find . -name '*_test.rb' -exec bash -c 'echo mv $0 ${0/test.rb/spec.rb}' {} \;काम करता है ? के रूप मेंfind . -name '*_test.rb' -exec bash -c 'echo mv $1 ${1/test.rb/spec.rb}' iAmArgumentZero {} \;
agtb

आपके सुझावों के लिए धन्यवाद, निश्चित
सीएसजी

यह क्लीयर करने के लिए धन्यवाद - मैंने केवल इसलिए टिप्पणी की क्योंकि मैंने _ का अर्थ विचार करते हुए बिताया है, यह सोचकर कि शायद $ _ ('_') का कुछ ट्रिक उपयोग डॉक्स में खोज करना बहुत कठिन है!)
एजीटीबी

9

यदि आप चाहें तो आप इसे बिना सेड के कर सकते हैं:

for i in `find -name '*_test.rb'` ; do mv $i ${i%%_test.rb}_spec.rb ; done

${var%%suffix}suffixके मूल्य से स्ट्रिप्सvar

या, यह sed का उपयोग करने के लिए:

for i in `find -name '*_test.rb'` ; do mv $i `echo $i | sed 's/test/spec/'` ; done

यह काम नहीं करता है ( sedएक) के रूप में स्वीकार किए जाते हैं उत्तर द्वारा समझाया।
अली

@ आलिया, यह काम करता है - जब मैंने जवाब लिखा तो मैंने खुद इसका परीक्षण किया। @ लार्समैन का स्पष्टीकरण लागू नहीं होता है for i in... ; do ... ; done, जो शेल के माध्यम से कमांड निष्पादित करता है और बैकटिक को समझता है।
वेन कॉनराड

9

आप उल्लेख करते हैं कि आप bashअपने शेल के रूप में उपयोग कर रहे हैं , जिस स्थिति में आपको वास्तव में आवश्यकता नहीं है findऔरsed आपके द्वारा बाद में किए जा रहे बैच को प्राप्त करने के लिए ...

मान लें कि आप bashअपने शेल के रूप में उपयोग कर रहे हैं :

$ echo $SHELL
/bin/bash
$ _

... और यह मानकर कि आपने तथाकथित globstarशेल विकल्प को सक्षम किया है :

$ shopt -p globstar
shopt -s globstar
$ _

... और अंत में आपने renameउपयोगिता स्थापित की है ( util-linux-ngपैकेज में पाया )

$ which rename
/usr/bin/rename
$ _

... तो आप बैच एक-लाइनर में नाम बदलने के रूप में प्राप्त कर सकते हैं:

$ rename _test _spec **/*_test.rb

( globstarशेल विकल्प यह सुनिश्चित करेगा कि बैश सभी मिलान वाली *_test.rbफ़ाइलों को ढूँढता है , चाहे वे कितनी भी गहराई से निर्देशिका पदानुक्रम में नेस्टेड हों ... help shoptविकल्प सेट करने का तरीका जानने के लिए उपयोग करें)


7

सबसे आसान तरीका :

find . -name "*_test.rb" | xargs rename s/_test/_spec/

सबसे तेज़ तरीका (आपके पास 4 प्रोसेसर हैं):

find . -name "*_test.rb" | xargs -P 4 rename s/_test/_spec/

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

आप अपने सिस्टम की सीमा का उपयोग करके जांच कर सकते हैं getconf ARG_MAX

अधिकांश लिनक्स सिस्टम पर आप उपयोग कर सकते हैं free -bया cat /proc/meminfoयह पता लगा सकते हैं कि आपको कितनी रैम के साथ काम करना है; अन्यथा, उपयोग करेंtop अपने सिस्टम गतिविधि मॉनिटर ऐप का या करें।

एक सुरक्षित तरीका (मान लें कि आपके पास काम करने के लिए 1000000 बाइट्स हैं):

find . -name "*_test.rb" | xargs -s 1000000 rename s/_test/_spec/

2

यहाँ मेरे लिए क्या काम किया है जब फ़ाइल नामों में उनमें स्थान था। नीचे दिए गए उदाहरण को .dip फ़ाइलों में .dar फ़ाइलों के लिए पुन: नाम दिया गया है:

find . -name "*.dar" -exec bash -c 'mv "$0" "`echo \"$0\" | sed s/.dar/.zip/`"' {} \;

2

इसके लिए आपको जरूरत नहीं है sed। आप पूरी तरह से एक प्रक्रिया प्रतिस्थापनwhile के findमाध्यम से परिणाम के साथ खिलाए गए लूप के साथ अकेले मिल सकते हैं ।

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

while IFS= read -r file; do
     echo "mv $file ${file%_test.rb}_spec.rb"  # remove "echo" when OK!
done < <(find -name "*_test.rb")

यह findफाइल को फिर से नाम देगा और स्ट्रिंग _test.rbको अंत से जोड़कर और जोड़कर _spec.rb

इस चरण के लिए हम शेल पैरामीटर विस्तार का उपयोग करते हैं जहां ${var%string}से सबसे छोटे मिलान पैटर्न "स्ट्रिंग" को हटा दिया जाता है $var

$ file="HELLOa_test.rbBYE_test.rb"
$ echo "${file%_test.rb}"          # remove _test.rb from the end
HELLOa_test.rbBYE
$ echo "${file%_test.rb}_spec.rb"  # remove _test.rb and append _spec.rb
HELLOa_test.rbBYE_spec.rb

एक उदाहरण देखें:

$ tree
.
├── ab_testArb
├── a_test.rb
├── a_test.rb_test.rb
├── b_test.rb
├── c_test.hello
├── c_test.rb
└── mydir
    └── d_test.rb

$ while IFS= read -r file; do echo "mv $file ${file/_test.rb/_spec.rb}"; done < <(find -name "*_test.rb")
mv ./b_test.rb ./b_spec.rb
mv ./mydir/d_test.rb ./mydir/d_spec.rb
mv ./a_test.rb ./a_spec.rb
mv ./c_test.rb ./c_spec.rb

आपका बहुत बहुत धन्यवाद! इसने मुझे आसानी से सभी फ़ाइल नामों से .gz को आसानी से हटाने में मदद की। while IFS= read -r file; do mv $file ${file%.gz}; done < <(find -type f -name "*.gz")
विनय विस

1
@CasualCoder को पढ़कर अच्छा लगा कि :) नोट आप सीधे कह सकते हैं find .... -exec mv ...। इसके अलावा, सावधान रहें $fileक्योंकि यह रिक्त स्थान होने पर विफल हो जाएगा। बेहतर उपयोग उद्धरण "$file"
फेडोरक्वी 'एसओ ने

1

अगर आपके पास रूबी (1.9+) है

ruby -e 'Dir["**/*._test.rb"].each{|x|test(?f,x) and File.rename(x,x.gsub(/_test/,"_spec") ) }'

1

रामतम के उत्तर में जो मुझे पसंद है, खोज भाग ठीक काम करता है, लेकिन शेष भाग में रिक्त स्थान नहीं है। मैं sed से परिचित नहीं हूँ, लेकिन मैं उस उत्तर को संशोधित करने में सक्षम था:

find . -name "*_test.rb" | perl -pe 's/^((.*_)test.rb)$/"\1" "\2spec.rb"/' | xargs -n2 mv

मुझे वास्तव में इस तरह के बदलाव की आवश्यकता थी क्योंकि मेरे उपयोग के मामले में अंतिम कमांड अधिक पसंद करता है

find . -name "olddir" | perl -pe 's/^((.*)olddir)$/"\1" "\2new directory"/' | xargs -n2 mv

1

मैंने इसे फिर से करने के लिए दिल नहीं किया है, लेकिन मैंने कमांडलाइन फाइंड सेड एक्सक के जवाब में यह लिखा है । वहाँ पूछने वाला जानना चाहता था कि एक पूरे पेड़ को कैसे स्थानांतरित किया जाए, संभवतः एक निर्देशिका या दो को छोड़कर, और स्ट्रिंग वाली सभी फ़ाइलों और निर्देशिकाओं का नाम बदलें। "पुराने" के बजाय करने के लिए होते हैं "नई"

के अतिरिक्त श्रमसाध्य क्रिया के साथ कैसे का वर्णन करने केनीचे , यह विधि इस भी अद्वितीय हो सकती है कि इसमें अंतर्निर्मित डीबगिंग शामिल है। यह मूल रूप से लिखे गए संकलन के अलावा कुछ भी नहीं करता है और एक चर को बचाने के लिए सभी आज्ञाओं को मानता है जो यह अनुरोध किए गए कार्य को करने के लिए करना चाहिए।

यह स्पष्ट रूप से यथासंभव छोरों से बचा जाता है। इसके अतिरिक्तsedपैटर्न के एक से अधिक मिलान के लिए पुनरावर्ती खोज के जहाँ तक मुझे पता है कोई अन्य पुनरावृत्ति नहीं है।

और अंतिम, यह पूरी तरह से है null सीमांकित है - यह किसी भी फ़ाइल नाम के किसी भी चरित्र पर यात्रा को छोड़कर नहीं है null। मुझे नहीं लगता कि आपके पास ऐसा होना चाहिए।

वैसे, यह वास्तव में तेजी से है। देखो:

% _mvnfind() { mv -n "${1}" "${2}" && cd "${2}"
> read -r SED <<SED
> :;s|${3}\(.*/[^/]*${5}\)|${4}\1|;t;:;s|\(${5}.*\)${3}|\1${4}|;t;s|^[0-9]*[\t]\(mv.*\)${5}|\1|p
> SED
> find . -name "*${3}*" -printf "%d\tmv %P ${5} %P\000" |
> sort -zg | sed -nz ${SED} | read -r ${6}
> echo <<EOF
> Prepared commands saved in variable: ${6}
> To view do: printf ${6} | tr "\000" "\n"
> To run do: sh <<EORUN
> $(printf ${6} | tr "\000" "\n")
> EORUN
> EOF
> }
% rm -rf "${UNNECESSARY:=/any/dirs/you/dont/want/moved}"
% time ( _mvnfind ${SRC=./test_tree} ${TGT=./mv_tree} \
> ${OLD=google} ${NEW=replacement_word} ${sed_sep=SsEeDd} \
> ${sh_io:=sh_io} ; printf %b\\000 "${sh_io}" | tr "\000" "\n" \
> | wc - ; echo ${sh_io} | tr "\000" "\n" |  tail -n 2 )

   <actual process time used:>
    0.06s user 0.03s system 106% cpu 0.090 total

   <output from wc:>

    Lines  Words  Bytes
    115     362   20691 -

    <output from tail:>

    mv .config/replacement_word-chrome-beta/Default/.../googlestars \
    .config/replacement_word-chrome-beta/Default/.../replacement_wordstars        

नोट: ऊपर functionकी संभावना के GNUसंस्करणों की आवश्यकता होगी sedऔर findठीक से संभाल करने के लिएfind printf और sed -z -eऔर:;recursive regex test;t कॉल। यदि ये आपके लिए उपलब्ध नहीं हैं, तो कार्यक्षमता को कुछ मामूली समायोजन के साथ दोहराया जा सकता है।

यह वह सब कुछ करना चाहिए जो आप शुरू से अंत तक बहुत कम उपद्रव के साथ करना चाहते थे। मैंने forkसाथ दिया था sed, लेकिन मैं कुछ sedपुनरावर्ती शाखाओं में बँधने का अभ्यास भी कर रहा था, इसलिए मैं यहाँ हूँ। यह एक नाई के स्कूल में एक छूट बाल कटवाने की तरह है, मुझे लगता है। यहाँ वर्कफ़्लो है:

  • rm -rf ${UNNECESSARY}
    • मैंने जानबूझकर कोई भी कार्यात्मक कॉल छोड़ा है जो किसी भी प्रकार के डेटा को हटा या नष्ट कर सकता है। आप उल्लेख करते हैं कि ./appअवांछित हो सकता है। इसे हटाएं या इसे पहले से कहीं और स्थानांतरित करें, या, वैकल्पिक रूप से, आप इसे \( -path PATTERN -exec rm -rf \{\} \)नियमित रूप से findप्रोग्राम करने के लिए एक रूटीन में बना सकते हैं , लेकिन यह सब आपका है।
  • _mvnfind "${@}"
    • इसके तर्कों की घोषणा करें और कार्यकर्ता फ़ंक्शन को कॉल करें। ${sh_io}इसमें विशेष रूप से महत्वपूर्ण है कि यह फ़ंक्शन से रिटर्न बचाता है। ${sed_sep}एक सेकंड में आता है; यह एक मनमाना स्ट्रिंग sedहै जो फ़ंक्शन में पुनरावृत्ति को संदर्भित करने के लिए उपयोग किया जाता है । यदि ${sed_sep}किसी ऐसे मूल्य पर सेट किया गया है जो संभवतः आपके किसी भी पथ में पाया जा सकता है- या फ़ाइल-नामों पर कार्य किया गया है ... ठीक है, बस इसे न होने दें।
  • mv -n $1 $2
    • पूरे पेड़ को शुरू से ही स्थानांतरित कर दिया गया है। यह बहुत सारे सिरदर्द को बचाएगा; मुझ पर विश्वास करो। बाकी जो आप करना चाहते हैं - नाम बदलना - बस फाइलसिस्टम मेटाडेटा का मामला है। यदि आप, उदाहरण के लिए, इसे एक ड्राइव से दूसरे में, या किसी भी प्रकार की फ़ाइल सिस्टम सीमाओं में स्थानांतरित कर रहे हैं, तो आप एक बार एक कमांड के साथ ऐसा करना बेहतर समझते हैं। यह भी सुरक्षित है। के -noclobberलिए निर्धारित विकल्प पर ध्यान दें mv; जैसा कि लिखा गया है, यह फ़ंक्शन उस जगह पर नहीं रखा जाएगा ${SRC_DIR}जहां ${TGT_DIR}पहले से मौजूद है।
  • read -R SED <<HEREDOC
    • मैंने सभी सीड्स कमांड्स को यहां रखा है ताकि वे झंझटों से बच सकें और नीचे चरने के लिए उन्हें चर में पढ़ सकें। नीचे स्पष्टीकरण।
  • find . -name ${OLD} -printf
    • हम findप्रक्रिया शुरू करते हैं। साथ findहम केवल कुछ भी है कि नाम बदलने की जरूरत है क्योंकि हम पहले से ही जगह-टू-जगह के सभी किया था के लिए खोज mvसमारोह का पहला आदेश के साथ आपरेशनों। उदाहरण के लिए, कॉल की findतरह कोई प्रत्यक्ष कार्यवाही करने के execबजाय, हम इसका उपयोग कमांड-लाइन को गतिशील रूप से बनाने के लिए करते हैं -printf
  • %dir-depth :tab: 'mv '%path-to-${SRC}' '${sed_sep}'%path-again :null delimiter:'
    • findउन फ़ाइलों का पता लगाने के बाद, जिनकी हमें सीधे आवश्यकता होती है और कमांड ( अधिकांश ) को प्रिंट करता है , जिन्हें हमें आपके नाम बदलने की प्रक्रिया की आवश्यकता होगी। %dir-depthहमला बोला पर प्रत्येक पंक्ति के आरंभ सुनिश्चित करने के लिए हम एक माता पिता वस्तु है कि अभी तक का नाम बदलने की के साथ एक फ़ाइल या पेड़ में निर्देशिका का नाम बदलने की कोशिश नहीं कर रहे मदद मिलेगी। findअपने फाइलसिस्टम ट्री को चलने के लिए सभी प्रकार की अनुकूलन तकनीकों का उपयोग करता है और यह एक निश्चित बात नहीं है कि यह उन डेटा को लौटाएगा जो हमें एक सुरक्षित-संचालन संचालन के लिए चाहिए। यही कारण है कि हम अगले ...
  • sort -general-numerical -zero-delimited
    • हम सभी के findउत्पादन को आधार पर क्रमबद्ध करते हैं %directory-depthताकि $ {SRC} के संबंध में निकटतम पथ पहले काम कर सकें। यह mvगैर-मौजूद स्थानों में फ़ाइलों को शामिल करने वाली संभावित त्रुटियों से बचा जाता है , और यह पुनरावर्ती लूपिंग के लिए आवश्यकता को कम करता है। ( वास्तव में, आप एक लूप खोजने के लिए कठोर हो सकते हैं )
  • sed -ex :rcrs;srch|(save${sep}*til)${OLD}|\saved${SUBSTNEW}|;til ${OLD=0}
    • मुझे लगता है कि यह पूरी स्क्रिप्ट में एकमात्र लूप है, और यह केवल %Pathप्रत्येक स्ट्रिंग के लिए दूसरे मुद्रित पर लूप करता है अगर इसमें एक से अधिक $ {OLD} मान होता है जिसे प्रतिस्थापित करने की आवश्यकता हो सकती है। अन्य सभी समाधानों की मैंने कल्पना की है कि इसमें एक दूसरी sedप्रक्रिया शामिल है , और जबकि एक छोटा लूप वांछनीय नहीं हो सकता है, निश्चित रूप से यह स्पानिंग को धड़कता है और एक पूरी प्रक्रिया को भूल जाता है।
    • तो मूल रूप से क्या sed यहाँ $ {sed_sep} की खोज की जाती है, फिर, इसे पाए जाने पर, इसे सहेजता है और यह सभी वर्णों का सामना करता है जब तक कि इसे $ {OLD} नहीं मिल जाता है, जो इसके बाद $ {NEW} से बदल जाता है। यह तब $ {sed_sep} पर वापस जाता है और $ {OLD} के लिए फिर से दिखता है, अगर यह स्ट्रिंग में एक से अधिक बार होता है। यदि यह नहीं पाया जाता है, तो यह संशोधित स्ट्रिंग को प्रिंट करता है stdout(जो इसे फिर अगले पकड़ता है) और लूप को समाप्त करता है।
    • यह पूरी स्ट्रिंग को पार्स करने से बचता है, और यह सुनिश्चित करता है कि mvकमांड स्ट्रिंग की पहली छमाही , जिसमें $ {OLD} को शामिल करना आवश्यक है, इसमें शामिल है, और दूसरी छमाही को बदलने के लिए जितनी बार आवश्यक है उतनी बार बदल दिया जाता है $ {OLD} नाम mvगंतव्य पथ से।
  • sed -ex...-ex search|%dir_depth(save*)${sed_sep}|(only_saved)|out
    • यहाँ दो -execकॉल एक दूसरे के बिना होते हैं fork। पहले में, जैसा कि हमने देखा है, हम mvकमांड को find'' -printfफंक्शन कमांड '' द्वारा दिए गए आवश्यकतानुसार संशोधित करते हैं, ताकि $ {OLD} के सभी संदर्भों को $ {NEW} में ठीक से बदल सकें, लेकिन ऐसा करने के लिए हमें कुछ का उपयोग करना होगा मनमाना संदर्भ बिंदु जो अंतिम आउटपुट में शामिल नहीं होना चाहिए। इसलिए एक बार जब sedइसे पूरा करने की आवश्यकता होती है, तो हम इसे पास करने से पहले होल्ड-बफर से इसके संदर्भ बिंदुओं को मिटा देने का निर्देश देते हैं।

और अब हम वापस आ गए हैं

read एक कमांड मिलेगा जो इस तरह दिखता है:

% mv /path2/$SRC/$OLD_DIR/$OLD_FILE /same/path_w/$NEW_DIR/$NEW_FILE \000

यह readउस ${msg}रूप में होगा ${sh_io}जिसकी जांच समारोह के बाहर की जा सकती है।

ठंडा।

-माइक


1

मैं onitake द्वारा सुझाए गए उदाहरणों का पालन करते हुए रिक्त स्थान के साथ फ़ाइल नाम को संभालने में सक्षम था ।

यह नहीं टूटता है अगर पथ में रिक्त स्थान या स्ट्रिंग है test:

find . -name "*_test.rb" -print0 | while read -d $'\0' file
do
    echo mv "$file" "$(echo $file | sed s/test/spec/)"
done

1

यह एक उदाहरण है जिसे सभी मामलों में काम करना चाहिए। पुनरावर्ती काम करता है, बस शेल की आवश्यकता है, और रिक्त स्थान के साथ फ़ाइलों के नामों का समर्थन करें।

find spec -name "*_test.rb" -print0 | while read -d $'\0' file; do mv "$file" "`echo $file | sed s/test/spec/`"; done

0
$ find spec -name "*_test.rb"
spec/dir2/a_test.rb
spec/dir1/a_test.rb

$ find spec -name "*_test.rb" | xargs -n 1 /usr/bin/perl -e '($new=$ARGV[0]) =~ s/test/spec/; system(qq(mv),qq(-v), $ARGV[0], $new);'
`spec/dir2/a_test.rb' -> `spec/dir2/a_spec.rb'
`spec/dir1/a_test.rb' -> `spec/dir1/a_spec.rb'

$ find spec -name "*_spec.rb"
spec/dir2/b_spec.rb
spec/dir2/a_spec.rb
spec/dir1/a_spec.rb
spec/dir1/c_spec.rb

आह..ई मुझे शेल स्क्रिप्ट में लॉजिक डालने के अलावा अन्य सेड का इस्तेमाल करने के तरीके के बारे में पता नहीं है और इसे निष्पादन में कॉल करें। शुरू में sed का उपयोग करने की आवश्यकता नहीं देखी
दामोदरन R

0

आपका प्रश्न sed के बारे में लगता है, लेकिन पुनरावर्ती नाम बदलने के अपने लक्ष्य को पूरा करने के लिए, मैं निम्नलिखित सुझाव दूंगा, बेशर्मी से एक और जवाब जो मैंने यहां दिया था से फट गया: पुनरावर्ती नाम फिर से

#!/bin/bash
IFS=$'\n'
function RecurseDirs
{
for f in "$@"
do
  newf=echo "${f}" | sed -e 's/^(.*_)test.rb$/\1spec.rb/g'
    echo "${f}" "${newf}"
    mv "${f}" "${newf}"
    f="${newf}"
  if [[ -d "${f}" ]]; then
    cd "${f}"
    RecurseDirs $(ls -1 ".")
  fi
done
cd ..
}
RecurseDirs .

यदि आप विकल्प निर्धारित नहीं करते हैं तो sedभागने के बिना काम कैसे होता है ?()-r
mikeserv

0

बर्तनों को खोजने और नियमित अभिव्यक्ति प्रकार के साथ नाम बदलने का अधिक सुरक्षित तरीका:

  mkdir ~/practice

  cd ~/practice

  touch classic.txt.txt

  touch folk.txt.txt

".Txt.txt" एक्सटेंशन को निम्नानुसार निकालें -

  cd ~/practice

  find . -name "*txt" -execdir sh -c 'mv "$0" `echo "$0" | sed -r 's/\.[[:alnum:]]+\.[[:alnum:]]+$//'`' {} \;

यदि आप के स्थान पर + का उपयोग करते हैं; बैच मोड पर काम करने के लिए, उपरोक्त कमांड केवल पहली मिलान वाली फ़ाइल का नाम बदलेगी, लेकिन 'खोज' द्वारा फ़ाइल मिलान की पूरी सूची नहीं।

  find . -name "*txt" -execdir sh -c 'mv "$0" `echo "$0" | sed -r 's/\.[[:alnum:]]+\.[[:alnum:]]+$//'`' {} +

0

यहाँ एक अच्छा oneliner है जो चाल करता है। सैड इस अधिकार को संभाल नहीं सकता है, खासकर अगर कई वेरिएबल्स को xargs के साथ पारित किया जाता है -n 2. एक बैश सबस्टेशन इसे आसानी से संभाल सकता है:

find ./spec -type f -name "*_test.rb" -print0 | xargs -0 -I {} sh -c 'export file={}; mv $file ${file/_test.rb/_spec.rb}'

जोड़ने-टाइप -f केवल कदमों के लिए कदम संचालन को सीमित करेगा, -प्रिंट 0 रास्तों में रिक्त स्थान को संभाल लेगा।



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