অনুসন্ধান এবং সেড ব্যবহার করে পুনরাবৃত্তভাবে ফাইলগুলির নাম পরিবর্তন করুন


87

আমি একগুচ্ছ ডিরেক্টরিতে যেতে চাই এবং তার পরিবর্তে _spec.rb এ শেষ হওয়া সমস্ত ফাইলের নাম পরিবর্তন করতে চাই _est.rb এ। এটি এমন কিছু যা আমি কখনই ব্যাশ দিয়ে কীভাবে করব তা ঠিক বুঝতে পারি নি তাই এবার ভাবলাম এটিকে পেরেক দেওয়ার জন্য আমি কিছু চেষ্টা করব। আমি এতদূর এগিয়ে এসেছি যদিও, আমার সেরা চেষ্টাটি হ'ল:

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

এনবি: এক্সিকিউট করার পরে একটি অতিরিক্ত প্রতিধ্বনি রয়েছে যাতে কমান্ডটি পরীক্ষা করার সময় রানের পরিবর্তে মুদ্রিত হয়।

আমি যখন এটি চালিত করি তখন প্রতিটি মিলে যাওয়া ফাইলের নামের আউটপুট হয়:

mv original original

অর্থাৎ সেড দ্বারা প্রতিস্থাপন হারিয়ে গেছে। কৌশলটি কী?


বিটিডাব্লু, আমি সচেতন যে একটি নাম পরিবর্তন কমান্ড আছে তবে আমি সত্যিই সেড ব্যবহার করে এটি কীভাবে করব তা অনুগ্রহ করতে চাই যাতে ভবিষ্যতে আরও শক্তিশালী কমান্ড করতে পারি।
opsb

4
ক্রস পোস্ট করবেন না দয়া করে ।
ডেনিস উইলিয়ামসন

উত্তর:


32

sedস্ট্র্যাপটি {}ইনপুট হিসাবে গ্রহণ করে কারণ এটি যাচাই করা যেতে পারে:

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

যা foofooডিরেক্টরিতে প্রতিটি ফাইলের জন্য পুনরাবৃত্তভাবে মুদ্রণ করে । এই আচরণের কারণ হ'ল পাইপলাইন একবার শেল দ্বারা কার্যকর করা হয়, যখন এটি সম্পূর্ণ কমান্ডটি প্রসারিত করে।

sedপাইপলাইনটি এমনভাবে উদ্ধৃত করার কোনও উপায় নেই যা findপ্রতিটি ফাইলের জন্য এটি কার্যকর করে, যেহেতু findশেলের মাধ্যমে কমান্ডগুলি কার্যকর করে না এবং পাইপলাইন বা ব্যাককোটিসের কোনও ধারণা নেই। জিএনইউ ফাইন্ডুলস ম্যানুয়ালটি পৃথক শেল স্ক্রিপ্টে পাইপলাইন স্থাপন করে কীভাবে অনুরূপ কাজ সম্পাদন করবে তা ব্যাখ্যা করে:

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

(কিছু sh -cকমান্ডে ব্যবহার করার কিছু বিভ্রান্ত উপায় এবং এক টন কোট থাকতে পারে, তবে আমি চেষ্টা করব না))


27
যারা এখানে sh -c এর বিকৃত ব্যবহার সম্পর্কে ভাবছেন তারা হলেন: সুনির্দিষ্ট-নাম "* _test.rb" -exec sh -c 'ইকো এমভি "$ 1" "$ (প্রতিধ্বনি" $ 1 "| সেড এস / টেস্ট.আরবি \ $ / spec.rb /) "'_ {} \;
opsb

4
@opsb এই হ্যাকটি কিসের জন্য? দুর্দান্ত সমাধান - তবে আমি রামটাম উত্তরটি আরও পছন্দ করি :)
আইআরএস

চিয়ার্স! আমাকে অনেক মাথাব্যথা বাঁচিয়েছে। সম্পূর্ণতার জন্য এইভাবে আমি এটি কোনও স্ক্রিপ্টে পাইপ করব: সন্ধান করুন। -নাম "ফাইল" -exec sh /path/to/script.sh {} \;
সোভেন এম

131

এটিকে সমাধান করার জন্য আসল সমস্যার সর্বাধিক নিকটে সম্ভবত 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

4
ঠিক এটাই আমি খুঁজছিলাম। সাদা স্থানের সমস্যার জন্য খুব খারাপ (যদিও আমি এটি পরীক্ষা করিনি)। তবে আমার বর্তমান প্রয়োজনের জন্য এটি নিখুঁত। আমি প্রথমে "এমআরজেস" এর পরামিতি হিসাবে "এমভি" এর পরিবর্তে "প্রতিধ্বনি" দিয়ে এটি পরীক্ষা করার পরামর্শ দেব।
মিশেল ডাল'আগটা

4
যদি আপনার পাথগুলিতে শ্বেত স্পেস মোকাবেলা করতে হয় এবং আপনি জিএনইউ সেড> = 4.2.2 ব্যবহার করছেন তবে আপনি -zবিকল্পগুলি খুঁজে পেতে পারেন -print0এবং xargs সহ ব্যবহার করতে পারেন -0:find -name '*._test.rb' -print0 | sed -ze "p;s/test/spec/" | xargs -0 -n2 mv
ইভান পুরখিজার

সবচেয়ে ভালো সমাধান. সন্ধানী-এক্সেকের চেয়ে অনেক দ্রুত। আপনাকে ধন্যবাদ
মিগুয়েল এ। বালদি হারল

যদি কোনও 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

4
ফাইলের জন্য $ (সন্ধান করুন-নাম "* _test.rb"); ইকো এমভি $ ফাইল করুন echo $file | sed s/_test.rb$/_spec.rb/; সম্পন্ন হয়েছে , একটি এক-লাইনের হয় তাই না?
ব্রেটিকাস

4
স্পেস সহ আপনার ফাইলের নাম থাকলে এটি কাজ করবে না। forএগুলি পৃথক কথায় বিভক্ত করবে। লুপটি কেবলমাত্র নিউলাইনগুলিতে বিভক্ত করার নির্দেশ দিয়ে আপনি এটিকে কাজ করতে পারেন। উদাহরণস্বরূপ সাইবারসিটি.বিজ / টিপস / হ্যান্ডলিং-ফাইল ফাইল-নামগুলি- স্পেসেস- ইন -ব্যাশ এইচটিএমএল দেখুন ।
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

আপনার পরামর্শের জন্য ধন্যবাদ, স্থির
সিএসজি

এটি পরিষ্কার করার জন্য ধন্যবাদ - আমি কেবল মন্তব্য করেছি কারণ আমি _ এর অর্থ নিয়ে ভাবতে কিছু সময় ব্যয় করেছি spent _ ('_' এর কিছু কৌশল ব্যবহার সম্ভবত
ডক্সে

9

আপনি চাইলে সেড ছাড়াই এটি করতে পারেন:

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

${var%%suffix}suffixমান থেকে রেখাচিত্রমালা var

বা, সেড ব্যবহার করে এটি করতে:

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

যখন ফাইলের নামগুলির মধ্যে ফাঁকা স্থান ছিল তখন আমার পক্ষে এটি কাজ করেছিল। নীচের উদাহরণটি পুনরাবৃত্তভাবে সমস্ত .arar ফাইলগুলিকে .zip ফাইলগুলিতে পুনরায় নামকরণ করে:

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")
বিনয় বিশ

4
@ ক্যাসুয়ালকোডারটি পড়ে খুব ভাল লাগল :) নোট আপনি সরাসরি বলতে পারেন 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

রামটামের উত্তরে যা আমি পছন্দ করি, সন্ধান অংশটি ঠিকঠাক কাজ করে তবে বাকী অংশটি যদি পথের ফাঁকা জায়গা থাকে না। আমি সেডের সাথে খুব বেশি পরিচিত নই, তবে আমি উত্তরটি সংশোধন করতে সক্ষম হয়েছি:

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-depthTacked সম্মুখের প্রতিটি লাইনে শুরুতে নিশ্চিত করার আমরা একটি পিতা বা মাতা বস্তু রয়েছে যা এখনও পুনরায় নাম দেওয়ার সঙ্গে একটি ফাইল বা গাছে ডিরেক্টরির নাম পরিবর্তন করার চেষ্টা করছি না সাহায্য করবে। findআপনার ফাইল সিস্টেম ট্রিটিতে হাঁটতে সমস্ত ধরণের অপ্টিমাইজেশান কৌশল ব্যবহার করে এবং এটি নিরাপদ-ক্রিয়াকলাপের জন্য আমাদের প্রয়োজনীয় ডেটা ফিরিয়ে দেবে তা নিশ্চিত বিষয় নয়। এই কারণেই আমরা পরবর্তী ...
  • sort -general-numerical -zero-delimited
    • আমরা findএর ভিত্তিতে সমস্তগুলির আউটপুটটি বাছাই করি %directory-depthযাতে $ {এসআরসি relationship এর সাথে নিকটতম পাথগুলি প্রথমে কাজ করা হয়। এটি mvঅস্তিত্বহীন লোকেশনে ফাইলগুলি যুক্ত সম্ভাব্য ত্রুটিগুলি এড়িয়ে চলে এবং এটি পুনরাবৃত্ত লুপিংয়ের জন্য প্রয়োজনীয়তা হ্রাস করে। ( প্রকৃতপক্ষে, আপনি কোনও লুপ খুঁজে পেতে খুব চাপে থাকতে পারেন )
  • sed -ex :rcrs;srch|(save${sep}*til)${OLD}|\saved${SUBSTNEW}|;til ${OLD=0}
    • আমি মনে করি এটি সম্পূর্ণ স্ক্রিপ্টের একমাত্র লুপ, এবং এটি %Pathপ্রতিটি স্ট্রিংয়ের জন্য দ্বিতীয় মুদ্রণের উপরে লুপ করে যদি এটির ক্ষেত্রে একাধিক {{ওল্ড} মান থাকে যা পরিবর্তনের প্রয়োজন হতে পারে} অন্যান্য সমস্ত সমাধান যা আমি কল্পনা করেছিলাম একটি দ্বিতীয় sedপ্রক্রিয়া জড়িত , এবং একটি সংক্ষিপ্ত লুপটি কাম্য নাও হতে পারে, অবশ্যই এটি বিস্তৃত হয় এবং একটি সম্পূর্ণ প্রক্রিয়া কাঁটাচামচ করে।
    • সুতরাং মূলত sedএখানে যা করা আছে তা হ'ল} {সেড_সেসপ for অনুসন্ধান করা, তারপরে এটি খুঁজে পেয়ে এটি সংরক্ষণ করে এবং সমস্ত অক্ষর এটির মুখোমুখি হয় যতক্ষণ না এটি $ {পুরানো finds সন্ধান করে, যা এরপরে এটি $ {NEW with দিয়ে প্রতিস্থাপন করে} এরপরে এটি $ $ sed_sep to এ ফিরে যায় এবং আবার স্ট্রিংয়ের ক্ষেত্রে এটি একাধিকবার ঘটে case {OLD for এর জন্য আবার সন্ধান করে। যদি এটি না পাওয়া যায় তবে এটি পরিবর্তিত স্ট্রিংটি মুদ্রণ করে stdout(এটি এটি পরে আবার ধরা পড়ে) এবং লুপটি শেষ করে।
    • এটি পুরো স্ট্রিংটিকে বিশ্লেষণ করা এড়ানো যায় এবং নিশ্চিত করে যে mvকমান্ড স্ট্রিংয়ের প্রথমার্ধে অবশ্যই $ {ওল্ড include অন্তর্ভুক্ত করা দরকার, এটি অন্তর্ভুক্ত করে এবং দ্বিতীয় অর্ধেকটি মুছে ফেলার জন্য যতবার পরিবর্তন করা হয় Destination {ওল্ড} mvএর গন্তব্য পথের নাম ।
  • sed -ex...-ex search|%dir_depth(save*)${sed_sep}|(only_saved)|out
    • এখানে দুটি -execকল একটি সেকেন্ড ছাড়াই ঘটে fork। প্রথম, আমরা দেখা করেছি, আমরা পরিবর্তন mvকমান্ড হিসাবে দ্বারা সরবরাহকৃত findএর -printfপ্রয়োজনীয় হিসাবে ফাংশন কমান্ড সঠিকভাবে $ {নতুন} এ $ {পুরোনো} এর সমস্ত রেফারেন্স পরিবর্তন করতে, কিন্তু অর্ডার কাজ করার জন্য তাই আমরা কিছু ব্যবহার ছিল যথেচ্ছ রেফারেন্স পয়েন্টগুলি চূড়ান্ত আউটপুটে অন্তর্ভুক্ত করা উচিত নয়। সুতরাং একবারে sedএটি করার দরকার সমস্ত শেষ হয়ে গেলে , আমরা এটিটি পাশ করার আগে হোল্ড-বাফার থেকে এর রেফারেন্স পয়েন্টগুলি মুছে ফেলার নির্দেশ দিই।

এবং এখনই আমরা পিছনে আছি

read এই মত দেখাচ্ছে এমন একটি আদেশ পাবেন:

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

এটি readএটি ফাংশনের বাইরে ইচ্ছামত যাচাই করা যেতে পারে ${msg}হিসাবে এটি হবে ${sh_io}

শীতল।

-মাইক


1

অনাইটেক প্রস্তাবিত উদাহরণ অনুসরণ করে আমি ফাঁকা জায়গাগুলির ফাইল নামগুলি পরিচালনা করতে সক্ষম হয়েছি।

এই না ভঙ্গ করেছো পথ স্পেস বা স্ট্রিং ধারণ করে 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

আহ..আমি শেল স্ক্রিপ্টে লজিক লাগানো ছাড়াও সেড ব্যবহারের অন্য কোনও উপায় সম্পর্কে অবগত নই এবং তাকে এক্সিকিউটে কল করি। প্রাথমিকভাবে
সেড

0

আপনার প্রশ্নটি সেড সম্পর্কে বলে মনে হচ্ছে, তবে পুনরাবৃত্তকরণের পুনর্নবীকরণের আপনার লক্ষ্যটি অর্জন করার জন্য, আমি নীচের পরামর্শ দেব, আমি এখানে দেওয়া অন্য উত্তর থেকে নির্লজ্জভাবে ছিঁড়ে ফেললাম: ব্যাশে পুনরায় নামকরণ

#!/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?
মাইকজার্ভ

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

কৌতুকটি করে এমন একটি দুর্দান্ত অনেলাইনার এখানে। শেড এই অধিকারটি হ্যান্ডেল করতে পারে না, বিশেষত যদি একাধিক ভেরিয়েবল -n 2 দিয়ে xargs দ্বারা পাস হয় তবে একটি ব্যাশ সাবস্টিটিশনটি এটিকে সহজেই পরিচালনা করতে পারে:

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

-প্রকার -f যোগ করা কেবলমাত্র ফাইলগুলিতে সরানো ক্রিয়াকে সীমাবদ্ধ করবে, -প্রিন্ট 0 পাথের ফাঁকা স্থানগুলি পরিচালনা করবে।



আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.