একাধিক ফাইল পরিবর্তন করুন


194

নিম্নলিখিত কমান্ডটি সঠিকভাবে 2 টি ফাইলের সামগ্রী পরিবর্তন করছে।

sed -i 's/abc/xyz/g' xaa1 xab1 

তবে আমার যা করা দরকার তা হ'ল এই জাতীয় বেশ কয়েকটি ফাইল পরিবর্তনশীল এবং আমি ফাইলের নাম জানি না। আমি একটি কমান্ড লিখতে চাই যা বর্তমান ডিরেক্টরি থেকে শুরু করে সমস্ত ফাইল পড়বে xa*এবং sedফাইলের বিষয়বস্তু পরিবর্তন করতে হবে।


61
মানে sed -i 's/abc/xyz/g' xa*?
পল আর

3
এখানে উত্তর যথেষ্ট না। Unix.stackex بدل.com
ইসহাক

উত্তর:


135

এখনো ভাল:

for i in xa*; do
    sed -i 's/asd/dfg/g' $i
done

কারণ কতগুলি ফাইল রয়েছে তা কেউই জানে না এবং কমান্ড লাইন সীমাবদ্ধতা ভঙ্গ করা সহজ।

যখন খুব বেশি ফাইল থাকে তখন এখানে কী ঘটে থাকে:

# grep -c aaa *
-bash: /bin/grep: Argument list too long
# for i in *; do grep -c aaa $i; done
0
... (output skipped)
#

18
যদি এমন অনেকগুলি ফাইল থাকে তবে আপনি কমান্ডের কমান্ড লাইন সীমাটি ভেঙে ফেলবেন for। এটি থেকে নিজেকে রক্ষা করতে, আপনাকে ব্যবহার করতে হবেfind ... | xargs ...
গ্লেন জ্যাকম্যান

1
আমি বাস্তবায়ন জানি না, তবে "এক্সএ *" প্যাটার্নটি কোনও পর্যায়ে প্রসারিত হতে হবে। শেলটি এর forজন্য echoবা তার থেকে আলাদা করার জন্য কী আলাদা হয় grep?
গ্লেন জ্যাকম্যান

4
আপডেট উত্তর দেখুন। আপনার যদি আরও তথ্যের প্রয়োজন হয় তবে দয়া করে একটি সরকারী প্রশ্ন জিজ্ঞাসা করুন, যাতে লোকেরা আপনাকে সহায়তা করতে পারে।
লেনিক 5'12

5
সেড কমান্ডে, ফাঁকা জায়গাগুলির ফাইল নামগুলিতে শব্দ বিভাজন এড়াতে আপনার "$i"পরিবর্তে ব্যবহার করতে হবে $i। অন্যথায় এটি খুব সুন্দর।
ওয়াইল্ডকার্ড

4
তালিকাটি সম্পর্কে, আমি বিশ্বাস করি যে পার্থক্যটি forভাষা সংশ্লেষের অংশ, এমনকি একটি বিল্টিনও নয়। কারণ sed -i 's/old/new' *, *অবশ্যই সমস্তটির প্রসারকে সেড করার জন্য একটি আর্গলিস্ট হিসাবে পাস করতে হবে এবং আমি নিশ্চিত যে sedপ্রক্রিয়াটি এমনকি শুরুর আগেই এটি ঘটতে হবে। forলুপটি ব্যবহার করে , সম্পূর্ণ আরগলিস্টটি (সম্প্রসারণ *) কখনই কমান্ড হিসাবে পাস হয় না, কেবল শেল মেমোরিতে সংরক্ষিত হয় এবং এর মাধ্যমে পুনরাবৃত্তি হয়। যদিও এর জন্য আমার মোটেও কোনও রেফারেন্স নেই, এটি সম্ভবত পার্থক্য বলে মনে হয়। (আমি আরও জ্ঞানী কারও কাছ থেকে শুনতে চাই ...)
ওয়াইল্ডকার্ড

165

আমি অবাক হয়েছি যে কেউ সন্ধানের জন্য-এক্সেক যুক্তিটি উল্লেখ করেন নি, যা এই ধরণের ব্যবহারের ক্ষেত্রে ব্যবহৃত হয়, যদিও এটি প্রতিটি মিলে যাওয়া ফাইলের নামের জন্য একটি প্রক্রিয়া শুরু করবে:

find . -type f -name 'xa*' -exec sed -i 's/asd/dsg/g' {} \;

বিকল্পভাবে, কেউ xargs ব্যবহার করতে পারে, যা কম প্রক্রিয়া শুরু করবে:

find . -type f -name 'xa*' | xargs sed -i 's/asd/dsg/g'

বা আরো সহজভাবে ব্যবহার + Exec বৈকল্পিক পরিবর্তে ;খোঁজ মঞ্জুর subprocess কলের জন্য প্রতি একটি ফাইল চেয়ে আরো অনেক কিছুর জন্য দেখুন:

find . -type f -name 'xa*' -exec sed -i 's/asd/dsg/g' {} +

7
আমাকে এই উত্তরে কমান্ডটি এমনভাবে সংশোধন করতে হয়েছিল: find ./ -type f -name 'xa*' -exec sed -i '' 's/asd/dsg/g' {} \;এটি ফাইন্ড কমান্ডের জন্য অবস্থান ./এবং -iওএসএক্সের পরে একক একক উদ্ধৃতি ।
শেলবিডজ

ফাইন্ড কমান্ডটি ইলফোনসোর সরবরাহিত হিসাবে কাজ করে, এটি কেবলমাত্র ব্যাকআপসফিক্স প্যারামিটারের ./সমান .এবং তার পরে -iথাকে।
uhausbrand

-execবরাবর খোঁজ করার বিকল্প {} +হিসাবে বিবৃত সমস্যা সমাধানের জন্য যথেষ্ট, এবং সবচেয়ে প্রয়োজনীয়তা জন্য জরিমানা করা উচিত। তবে xargsসাধারণভাবে এটি আরও ভাল পছন্দ কারণ এটি -pবিকল্পের সাথে সমান্তরাল প্রক্রিয়াকরণও করতে দেয় । আপনার গ্লোব সম্প্রসারণ যখন আপনার কমান্ড লাইনের দৈর্ঘ্যের ওভারফ্লো করার পক্ষে যথেষ্ট পরিমাণে বেড়ে যায় তখন আপনি ক্রমিক ক্রম থেকে একটি স্পিডআপ থেকেও উপকৃত হতে পারেন।
অমিত নাইডু

78

আপনি একসাথে গ্রেপ এবং সেড ব্যবহার করতে পারেন। এটি আপনাকে পুনরুক্তি করে উপ-ডিরেক্টরিগুলি অনুসন্ধান করতে দেয়।

Linux: grep -r -l <old> * | xargs sed -i 's/<old>/<new>/g'
OS X: grep -r -l <old> * | xargs sed -i '' 's/<old>/<new>/g'

For grep:
    -r recursively searches subdirectories 
    -l prints file names that contain matches
For sed:
    -i extension (Note: An argument needs to be provided on OS X)

3
আমার জন্য এই পদ্ধতির grep -vবোনাসটি হ'ল আমি গিট ফোল্ডারগুলি এড়ানোর জন্য পিছলে যেতে পারতামgrep -rl <old> . | grep -v \.git | xargs sed -i 's/<old>/<new>/g'
মার্টিন লিন

ম্যাকের জন্য সেরা সমাধান!
মারকুইস ব্লাউন্ট 19

30

এই কমান্ডগুলি sedম্যাক ওএস এক্সের সাথে আসা ডিফল্টটিতে কাজ করবে না ।

থেকে man 1 sed:

-i extension
             Edit files in-place, saving backups with the specified
             extension.  If a zero-length extension is given, no backup 
             will be saved.  It is not recommended to give a zero-length
             extension when in-place editing files, as you risk corruption
             or partial content in situations where disk space is exhausted, etc.

চেষ্টা করা হয়েছে

sed -i '.bak' 's/old/new/g' logfile*

এবং

for i in logfile*; do sed -i '.bak' 's/old/new/g' $i; done

দুটোই ঠিকঠাক কাজ করে।


2
@ সুমেক এখানে ওএস এক্স-তে একটি উদাহরণ টার্মিনাল সেশন রয়েছে যা দেখায় যে সমস্ত উপস্থিতি প্রতিস্থাপন করা হয়েছে: গিটহাব গিস্ট
ফ্যানরোল

আমি নীচে ওয়ান-লাইনার সহ আমার সমস্ত ওয়েবসাইট কনফিগারেশন ফাইলগুলিতে দুটি পৃথক লাইন প্রতিস্থাপন করতে এটি ব্যবহার করেছি। sed -i.bak "s / supercache_proxy_config / proxy_includes \ / supercache_config / g; s / basic_proxy_config / প্রক্সি_ইনক্লাস \ / বেসিক_প্রক্সি_ফোন / জি" সাইটগুলি উপলভ্য / * যখন ফাইলের জন্য করা হয় তখন * .বাক ফাইলগুলি মুছতে ভুলবেন না সিস্টেম হাইজিনের খাতিরে।
জোশিয়ার

19

@ পলআর এটি একটি মন্তব্য হিসাবে পোস্ট করেছেন, তবে লোকেরা এটিকে একটি উত্তর হিসাবে দেখতে হবে (এবং এই উত্তরটি আমার প্রয়োজনের জন্য সবচেয়ে ভাল কাজ করে):

sed -i 's/abc/xyz/g' xa*

এটি মাঝারি পরিমাণে ফাইলের জন্য কাজ করবে, সম্ভবত দশকের ক্রমে, তবে লক্ষ লক্ষগুলির অর্ডারে নয়


ধরুন আপনার প্রতিস্থাপনগুলিতে আপনার ফরোয়ার্ড-স্ল্যাশ রয়েছে। ফাইলপথগুলির সাথে অন্য একটি উদাহরণ sed -i 's|auth-user-pass nordvpn.txt|auth-user-pass /etc/openvpn/nordvpn.txt|g' *.ovpn
লিও লোপল্ড হার্টজ 준영

10

আরও একটি বহুমুখী উপায় হ'ল find:

sed -i 's/asd/dsg/g' $(find . -type f -name 'xa*')

1
এই ফাইন্ড কমান্ডের আউটপুট প্রসারিত হয়, সুতরাং এটি সমস্যাটির সমাধান করে না। পরিবর্তে আপনার উচিত
এক্সেক

@erjoalgo এটি কাজ করে কারণ সেড কমান্ড একাধিক ইনপুট ফাইল পরিচালনা করতে পারে। ফাইন্ড কমান্ডের সম্প্রসারণ ঠিক এটির কাজ করার জন্য প্রয়োজন ছিল।
dkinzer

ফাইলের সংখ্যা যতক্ষণ না কমান্ড লাইন সীমাতে প্রবেশ না করে ততক্ষণ এটি কাজ করে।
ealfonso

এই সীমাটি কেবল মেশিনে উপলব্ধ মেমোরি সংস্থানগুলির উপর নির্ভরশীল এবং এটি নির্বাহের সীমা হিসাবে ঠিক একই।
ডিসকিনজার

4
এটি কেবল সত্য নয়। উপরের আপনার কমান্ডে, $ (সন্ধান করুন ...) একটি একক কমান্ডে প্রসারিত হবে, যা অনেকগুলি মেলানো ফাইল থাকলে খুব দীর্ঘ হতে পারে। যদি এটি দীর্ঘ হয় (উদাহরণস্বরূপ আমার সিস্টেমে সীমাটি 2097152 টি অক্ষরের কাছাকাছি থাকে) আপনি একটি ত্রুটি পেতে পারেন: "আর্গুমেন্টের তালিকা খুব দীর্ঘ" এবং আদেশটি ব্যর্থ হবে। এ সম্পর্কে কিছু পটভূমি পেতে দয়া করে এই ত্রুটিটি গুগল করুন।
ealfonso

2

আমি findঅনুরূপ কাজের জন্য ব্যবহার করছি । এটি বেশ সহজ: আপনার এটির পক্ষে যুক্তি হিসাবে এটি পাস করতে হবে sed:

sed -i 's/EXPRESSION/REPLACEMENT/g' `find -name "FILE.REGEX"`

এইভাবে আপনাকে জটিল লুপগুলি লিখতে হবে না এবং এটি দেখতে সহজ, আপনি কোন ফাইলগুলি পরিবর্তন করতে চলেছেন, তা চালানোর findআগে চালান sed



0

আপনি করতে পারেন

' এক্সএক্সএক্সএক্সএক্স ' টেক্সট আপনি সন্ধান করেন এবং এটিকে ' ইয়ে ' দিয়ে প্রতিস্থাপন করবেন

grep -Rn '**xxxx**' /path | awk -F: '{print $1}' | xargs sed -i 's/**xxxx**/**yyyy**/'

0

আপনি যদি কোনও স্ক্রিপ্ট চালাতে সক্ষম হন তবে আমি এখানে একই জাতীয় পরিস্থিতির জন্য যা করেছি:

sedকমান্ডের জন্য অভিধান / হ্যাশম্যাপ (এসোসিয়েটিভ অ্যারে) এবং ভেরিয়েবলগুলি ব্যবহার করে আমরা কয়েকটি স্ট্রিং প্রতিস্থাপন করতে অ্যারের মধ্য দিয়ে লুপ করতে পারি। একটি ওয়াইল্ডকার্ড অন্তর্ভুক্ত name_patternকরার সাথে name_pattern='File*.txt'একটি নির্দিষ্ট ডিরেক্টরিতে ( source_dir) একটি প্যাটার্ন (এটি এমন কিছু হতে পারে ) দিয়ে ফাইলগুলিতে স্থানের স্থান প্রতিস্থাপন করবে । সমস্ত পরিবর্তন লেখা রয়েছে logfiledestin_dir

#!/bin/bash
source_dir=source_path
destin_dir=destin_path
logfile='sedOutput.txt'
name_pattern='File.txt'

echo "--Begin $(date)--" | tee -a $destin_dir/$logfile
echo "Source_DIR=$source_dir destin_DIR=$destin_dir "

declare -A pairs=( 
    ['WHAT1']='FOR1'
    ['OTHER_string_to replace']='string replaced'
)

for i in "${!pairs[@]}"; do
    j=${pairs[$i]}
    echo "[$i]=$j"
    replace_what=$i
    replace_for=$j
    echo " "
    echo "Replace: $replace_what for: $replace_for"
    find $source_dir -name $name_pattern | xargs sed -i "s/$replace_what/$replace_for/g" 
    find $source_dir -name $name_pattern | xargs -I{} grep -n "$replace_for" {} /dev/null | tee -a $destin_dir/$logfile
done

echo " "
echo "----End $(date)---" | tee -a $destin_dir/$logfile

প্রথমত, জোড়া অ্যারে ঘোষিত হয়, প্রতিটি জোড়া একটি প্রতিস্থাপন স্ট্রিং, তাহলে তোমরা WHAT1জন্য প্রতিস্থাপন করা হবে FOR1এবং OTHER_string_to replaceজন্য প্রতিস্থাপন করা হবে string replacedফাইলের মধ্যে File.txt। লুপে অ্যারেটি পড়ে, জোড়ার প্রথম সদস্যটি পুনরুদ্ধার করা হয় replace_what=$iএবং দ্বিতীয়টি হিসাবে replace_for=$jfindকমান্ড অনুসন্ধান ডিরেক্টরির মধ্যে ফাইলের নাম (যে একটি ওয়াইল্ড কার্ড থাকতে পারে) এবং sed -iএকই ফাইল (গুলি) কি পূর্বে নির্ধারিত ছিল কমান্ড প্রতিস্থাপন করে। অবশেষে আমি grepফাইলগুলিতে করা পরিবর্তনগুলি লগ করতে লগফাইলে পুনর্নির্দেশ যুক্ত করেছি ।

এটি আমার পক্ষে কাজ করেছে GNU Bash 4.3 sed 4.2.2এবং ভাস্যনাভিকভের জবাবের উপর ভিত্তি করে লুপ ওভার ব্যাশ-এ টিপলস নিয়েছে

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