কিভাবে আমি একটি recursive অনুসন্ধান কমান্ড লাইন থেকে প্রতিস্থাপন করতে পারেন?


62

Bash বা zshell মত শেল ব্যবহার করে, কিভাবে আমি একটি recursive 'খুঁজে পেতে এবং প্রতিস্থাপন করতে পারেন? অন্য কথায়, আমি এই ডিরেক্টরি এবং এর সাবডিরেক্টরির সমস্ত ফাইলগুলিতে 'বার' দিয়ে 'foo' এর প্রতিটি ঘটনার প্রতিস্থাপন করতে চাই।


একই প্রশ্নের জন্য একটি বিকল্প উত্তর এখানে পাওয়া যাবে stackoverflow.com/questions/9704020/...
dunxd

উত্তর:


80

এই কমান্ডটি এটি করবে (ম্যাক ওএস এক্স লায়ন এবং কুবুন্টু লিনাক্স উভয় ক্ষেত্রেই পরীক্ষিত)।

# Recursively find and replace in files
find . -type f -name "*.txt" -print0 | xargs -0 sed -i '' -e 's/foo/bar/g'

এখানে কিভাবে এটা কাজ করে:

  1. find . -type f -name '*.txt' বর্তমান ডিরেক্টরি (খুঁজে পাওয়া যায় নি) . ) এবং নীচে, সব নিয়মিত ফাইল ( -type f ) যার নাম শেষ .txt
  2. | পরবর্তী কমান্ডের যে কমান্ডের আউটপুট (ফাইলের নামের একটি তালিকা) পাস করে
  3. xargs ঐ ফাইল নাম সংগ্রহ এবং এক এক তাদের এক হাতে sed
  4. sed -i '' -e 's/foo/bar/g' মানে "ব্যাকআপ ব্যতীত ফাইলটি সম্পাদনা করুন, এবং নিম্নলিখিত বিকল্পটি তৈরি করুন ( s/foo/bar ) লাইন প্রতি একাধিক বার ( /g ) "(দেখুন man sed )

লাইন 4 এ 'ব্যাকআপ ছাড়া' অংশটি আমার জন্য ঠিক আছে, যেহেতু আমি যে ফাইলগুলি পরিবর্তন করছি তা যেকোনোভাবে সংস্করণ নিয়ন্ত্রণের অধীনে রয়েছে, তাই ভুল হলে আমি সহজেই পূর্বাবস্থায় ফেরাতে পারি।


9
কখনও পাইপ ছাড়া xargs আউটপুট খুঁজে না -print0 বিকল্প। আপনার কমান্ড তাদের নামের মধ্যে স্পেস ইত্যাদি ফাইলগুলিতে ব্যর্থ হবে।
slhck

17
এছাড়াও, শুধু find -name '*.txt' -exec sed -i 's/foo/bar/g' {} + GNU সঙ্গে এই সব কি হবে।
Daniel Andersson

6
আমি পাই sed: can't read : No such file or directory যখন আমি রান find . -name '*.md' -print0 | xargs -0 sed -i '' -e 's/ä/ä/g', কিন্তু find . -name '*.md' -print0 অনেক ফাইল একটি তালিকা দেয়।
Martin Thoma

8
আমি আমার মধ্যে স্থান মুছে ফেলার জন্য এই কাজ করে -i এবং ''
Canadian Luke

3
মানে কি '' পরে sed -i কি হয় '' ভূমিকা?
Jas

22
find . -type f -name "*.txt" -exec sed -i'' -e 's/foo/bar/g' {} +

এই মুছে ফেলা হয় xargs নির্ভরতা।


4
এই GNU সঙ্গে কাজ করে না sed, তাই অধিকাংশ সিস্টেমে ব্যর্থ হবে। গনুহ sed আপনি মধ্যে কোন স্থান করা প্রয়োজন -i এবং ''
slhck

1
গৃহীত উত্তর এটি ব্যাখ্যা একটি ভাল কাজ করে। কিন্তু সঠিক সিনট্যাক্স ব্যবহার করার জন্য +1।
orodbhen

6

আপনি যদি জিট ব্যবহার করেন তবে আপনি এটি করতে পারেন:

git grep -lz foo | xargs -0 sed -i '' -e 's/foo/bar/g'

-l শুধুমাত্র ফাইল নাম তালিকা। -z প্রতিটি ফলাফলের পরে একটি নিল বাইট প্রিন্ট।

আমি এটি শেষ করতে পেরেছি কারণ কোনও প্রকল্পের কিছু ফাইল ফাইলটির শেষে একটি নতুন লাইন ছিল না, এবং এটি অন্য কোনও পরিবর্তন না করেও একটি নতুন লাইন যুক্ত করেছে। (ফাইলগুলি শেষ পর্যন্ত একটি নতুন লাইন থাকা উচিত কিনা তা নিয়ে কোনও মন্তব্য নেই।)


1
এই সমাধান জন্য বড় +1। বাকি find ... -print0 | xargs -0 sed ... সমাধানগুলি অনেক বেশি সময় নেয় না তবে এমন ফাইলগুলিতে নতুন লাইন যুক্ত করে যা ইতিমধ্যে একটি না থাকে, যা একটি গিট রেপোর ভিতরে কাজ করার সময় বিরক্তিকর। git grep তুলনা করে দ্রুত আলো হয়।
Josh Kupershmidt

3

এখানে আমার zsh / perl ফাংশন আমি এই জন্য ব্যবহার করি:

change () {
        from=$1 
        shift
        to=$1 
        shift
        for file in $*
        do
                perl -i.bak -p -e "s{$from}{$to}g;" $file
                echo "Changing $from to $to in $file"
        done
}

এবং আমি এটা ব্যবহার করে চালানো হবে

$ change foo bar **/*.java

(উদাহরণ স্বরূপ)


2

চেষ্টা করুন:

sed -i 's/foo/bar/g' $(find . -type f)

উবুন্টু 1২.04 এ পরীক্ষিত।

সাবডিরেক্টরি নাম এবং / অথবা ফাইলের নামগুলিতে স্পেস থাকে তবে এই কমান্ডটি কাজ করবে না, তবে যদি আপনি তাদের এই কমান্ডটি ব্যবহার না করেন তবে এটি কাজ করবে না।

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

http://linuxcommand.org/lc3_lts0020.php

"ফাইল নাম সম্পর্কে গুরুত্বপূর্ণ তথ্য" দেখুন


আপনার নামগুলিতে স্থান (গুলি) সহ ফাইল (গুলি) থাকলে এটি ব্যবহার করে দেখুন। (এমন একটি নিয়ম আছে যা বলে যে, "যদি কিছু সত্য বলে মনে হয় তবে এটি সম্ভবত।" যদি আপনি কোন সমাধানটি "আবিষ্কৃত" করেন যা অন্য কোনও তুলনায় কম কম্প্যাক্ট থাকে তবে অন্য কেউ 3½ বছরের মধ্যে পোস্ট করেছে, আপনাকে নিজেকে জিজ্ঞাসা করা উচিত কেন যে হতে পারে।)
Scott

1

এই শেল স্ক্রিপ্ট ব্যবহার করুন

আমি এখন এই শেল স্ক্রিপ্টটি ব্যবহার করি, যা অন্য উত্তরগুলি থেকে এবং ওয়েব অনুসন্ধান থেকে আমি যা শিখেছি তা সমন্বয় করে। আমি এটি একটি ফাইল বলা change আমার একটি ফোল্ডারে $PATH এবং কি chmod +x change

#!/bin/bash
function err_echo {
  >&2 echo "$1"
}

function usage {
  err_echo "usage:"
  err_echo '  change old new foo.txt'
  err_echo '  change old new foo.txt *.html'
  err_echo '  change old new **\*.txt'
  exit 1
}

[ $# -eq 0 ] && err_echo "No args given" && usage

old_val=$1
shift
new_val=$1
shift
files=$* # the rest of the arguments

[ -z "$old_val" ]  && err_echo "No old value given" && usage
[ -z "$new_val" ]  && err_echo "No new value given" && usage
[ -z "$files" ]    && err_echo "No filenames given" && usage

for file in $files; do
  sed -i '' -e "s/$old_val/$new_val/g" $file
done

0

আমার ব্যবহার ক্ষেত্রে আমি প্রতিস্থাপন চেয়েছিলেন foo:/Drive_Letter সঙ্গে foo:/bar/baz/xyz আমার ক্ষেত্রে আমি নিম্নলিখিত কোড দিয়ে এটি করতে সক্ষম হয়েছিলাম। আমি ফাইলের প্রচুর ছিল যেখানে একই ডিরেক্টরি অবস্থান ছিল।

find . -name "*.library" -print0 | xargs -0 sed -i '' -e 's/foo:\/Drive_Letter:/foo:\/bar\/baz\/xyz/g'

সাহায্য যে আশা করি।


0

উবুন্টু এবং সেন্টোসের উপর নিম্নোক্ত কমান্ডটি কাজ করে। যাইহোক, ওএস এক্স এর অধীনে আমি ত্রুটি পেয়েছি:

find . -name Root -exec sed -i 's/1.2.3.4\/home/foo.com\/mnt/' {} \;

sed: 1: "./Root": অবৈধ কমান্ড কোড।

যখন আমি xargs এর মাধ্যমে প্যারামিগুলিকে পাস করার চেষ্টা করি তখন এটি কোন ত্রুটি ছাড়াই কাজ করে:

find . -name Root -print0 | xargs -0 sed -i '' -e 's/1.2.3.4\/home/foo.com\/mnt/'

আপনি পরিবর্তন যে -i থেকে -i '' আপনি পরিবর্তিত যে আসলে তুলনায় আরো প্রাসঙ্গিক -exec থেকে -print0 | xargs -0। BTW, আপনি সম্ভবত প্রয়োজন হবে না -e
Scott
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.