বাশ কমান্ড থেকে একটি পাঠ্য ফাইলের অভ্যন্তরে সন্ধান করুন এবং প্রতিস্থাপন করুন


561

প্রদত্ত ইনপুট স্ট্রিংটির সন্ধান এবং প্রতিস্থাপনের সহজ উপায় কী abc, XYZফাইলটিতে বলুন এবং অন্য স্ট্রিংয়ের সাথে প্রতিস্থাপন করুন /tmp/file.txt?

আমি একটি অ্যাপ লিখন করছি এবং এসআরএইচ এর মাধ্যমে আদেশগুলি সম্পাদন করতে আয়রন পাইথন ব্যবহার করছি - তবে আমি ইউনিক্সকে এটি ভালভাবে জানি না এবং কী সন্ধান করতে হবে তা আমি জানি না।

আমি শুনেছি যে কমান্ড লাইন ইন্টারফেস ছাড়াও বাশ খুব শক্তিশালী স্ক্রিপ্টিং ভাষা হতে পারে। সুতরাং, যদি এটি সত্য হয় তবে আমি ধরে নিই যে আপনি এই জাতীয় ক্রিয়া করতে পারেন।

আমি কি এটি ব্যাশ দিয়ে করতে পারি এবং আমার লক্ষ্য অর্জনের সবচেয়ে সহজ (এক লাইন) স্ক্রিপ্টটি কী?

উত্তর:


927

সবচেয়ে সহজ উপায় হল সেড (বা পার্ল) ব্যবহার করা:

sed -i -e 's/abc/XYZ/g' /tmp/file.txt

যা সেড -iবিকল্পের কারণে একটি ইন-প্লেস সম্পাদনা করতে অনুরোধ করবে । এটি বাশ থেকে কল করা যেতে পারে।

আপনি যদি সত্যিই কেবল বাশ ব্যবহার করতে চান তবে নিম্নলিখিতগুলি কাজ করতে পারে:

while read a; do
    echo ${a//abc/XYZ}
done < /tmp/file.txt > /tmp/file.txt.t
mv /tmp/file.txt{.t,}

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


3
চালিত এমভি ব্যতীত শেড ব্যবহার করার মতো 'নন ব্যাশ' এর চেয়েও অনেক বেশি। আমি প্রায় একই প্রতিধ্বনি বলেছি, তবে এটি শেল বিল্টিন।
পাতলা

5
সেডের জন্য -i যুক্তি সোলারিসের জন্য বিদ্যমান নেই (এবং আমি অন্য কিছু বাস্তবায়নও ভাবি) তবে এটি মনে রাখবেন। এটি বুঝতে বেশ কয়েক মিনিট সময় কাটিয়েছেন ...
পঙ্কি

2
স্বরে নোট করুন: এর নিয়মিত প্রকাশ সম্পর্কে sed: s/..../..../ - Substituteএবং /g - Global
চেকসাম

89
invalid command code Cত্রুটি পান এমন ম্যাক ব্যবহারকারীদের জন্য নোট করুন ... স্থান-প্রতিস্থাপনের জন্য, বিএসডি পতাকাটির sedপরে একটি ফাইল এক্সটেনশন প্রয়োজন -iকারণ এটি প্রদত্ত এক্সটেনশন সহ একটি ব্যাকআপ ফাইল সংরক্ষণ করে। উদাহরণস্বরূপ: sed -i '.bak' 's/find/replace/' /file.txt আপনি খালি স্ট্রিং ব্যবহার করে ব্যাকআপটি এড়িয়ে যেতে পারেন:sed -i '' 's/find/replace/' /file.txt
অস্টিন

8
টিপ: আপনি যদি সংবেদনশীল পুনরাবৃত্তির ক্ষেত্রে মামলাটি চানs/abc/XYZ/gi
বোরিস ডি তেওহরভ

166

ফাইল ম্যানিপুলেশন সাধারণত বাশ দ্বারা করা হয় না, তবে বাশ দ্বারা চালিত প্রোগ্রামগুলি দ্বারা: যেমন:

perl -pi -e 's/abc/XYZ/g' /tmp/file.txt

-iসেটির উপরে ফ্ল্যাগ লাগাতে বলে একটি ইন-জায়গা প্রতিস্থাপন না।

man perlrunআসল ফাইলটির ব্যাকআপ কীভাবে নেওয়া যায় সে সম্পর্কে আরও বিশদ দেখুন ।


37
আমার মধ্যে পিউরিস্ট বলেছেন যে আপনি নিশ্চিত হতে পারবেন না যে পার্ল সিস্টেমে পাওয়া যাবে। তবে আজকাল এটি খুব কমই ঘটে। সম্ভবত আমি আমার বয়স দেখাচ্ছে।
পাতলা

3
আপনি আরও জটিল উদাহরণ দেখাতে পারেন। "Chdir / blah2" এর সাথে "chdir / blah2" প্রতিস্থাপন করার মতো কিছু। আমি চেষ্টা করেছি perl -pi -e 's/chdir (?:\\/[\\w\\.\\-]+)+/chdir blah/g' text, তবে প্যাটার্ন এবং নিম্নলিখিত শব্দের মধ্যে স্থান না থাকাতে আমি একটি ত্রুটি পেয়েছি -১ লাইন ১ এ অবনতিযুক্ত Un ?: \\ / at -e লাইন 1.
সিএমসিডিগ্রাগনকাই

: @CMCDragonkai এই উত্তর চেক করুন stackoverflow.com/a/12061491/2730528
আলফনসো সান্টিয়াগো

69

আমি যখন এতে হোঁচট খেয়েছি তখন আমি অবাক হয়ে গিয়েছিলাম ...

একটি replaceকমান্ড রয়েছে যা "mysql-server"প্যাকেজটি পাঠায়, তাই আপনি যদি এটি ইনস্টল করেন তবে এটি ব্যবহার করে দেখুন:

# replace string abc to XYZ in files
replace "abc" "XYZ" -- file.txt file2.txt file3.txt

# or pipe an echo to replace
echo "abcdef" |replace "abc" "XYZ"

man replaceএই সম্পর্কে আরও দেখুন ।


12
দুটি জিনিস এখানে সম্ভব: ক) replaceএকটি দরকারী স্বাধীন সরঞ্জাম এবং মাইএসকিউএল লোকেরা এটি আলাদাভাবে ছেড়ে দেয় এবং এর উপর নির্ভর করে খ) replaceকিছুটা মাইএসকিউএল o_O প্রয়োজন হয়, কোনওভাবেই মাইএসকিউএল-সার্ভার ইনস্টল করা ভুল কাজ হতে পারে would :)
ফিলিপ হোয়াইটহাউস

শুধু ম্যাকের জন্য কাজ করে? আমার উবুন্টুতে আমি সেন্ডোস সেই আদেশের অস্তিত্ব নেই
পল

1
কারণ আপনার mysql-serverপ্যাকেজ ইনস্টল করা নেই। @ রায়েরো দ্বারা চিহ্নিত হিসাবে replaceএটি এর অংশ।
Phius

2
"সতর্কতা: প্রতিস্থাপনটি অবচিত করা হয়েছে এবং ভবিষ্যতের সংস্করণে সরানো হবে।"
স্টিভেন ওয়াচন

1
উইন্ডোতে রিপ্লেস কমান্ডটি না চালাতে সাবধান! উইন্ডোজে REPLACE কমান্ডটি ফাইলগুলির দ্রুত প্রতিলিখনের জন্য। এই আলোচনার সাথে প্রাসঙ্গিক নয়।
মাওর

52

এটি একটি পুরানো পোস্ট তবে @ সেন্টুরীয়ান হিসাবে যে কেউ ভেরিয়েবলগুলি ব্যবহার করতে চাইছেন তাদের জন্য বলেছেন যে একক উদ্ধৃতি অর্থ কিছুই প্রসারিত হবে না।

ভেরিয়েবলগুলি পাওয়ার সহজ উপায় হ'ল স্ট্রিং কনটেনটেশন করা যেহেতু এটি ব্যাশের মধ্যে জুস্টপজেশন দ্বারা করা হয় নিম্নলিখিত নীচে কাজ করা উচিত:

sed -i -e "s/$var1/$var2/g" /tmp/file.txt

39

অন্যান্য শেলগুলির মতো বাশও অন্যান্য কমান্ডের সমন্বয় সাধনের এক সরঞ্জাম। সাধারণত আপনি স্ট্যান্ডার্ড ইউএনআইএক্স কমান্ড ব্যবহার করার চেষ্টা করবেন তবে আপনি অবশ্যই নিজের সংকলিত প্রোগ্রামগুলি, অন্যান্য শেল স্ক্রিপ্টস, পাইথন এবং পার্ল স্ক্রিপ্টস ইত্যাদিসহ কিছু চাইলে বাশ ব্যবহার করতে পারেন you

এই ক্ষেত্রে, এটি করার কয়েকটি উপায় রয়েছে।

আপনি যদি কোনও ফাইল পড়তে চান এবং অন্য ফাইলটিতে লিখতে চান, সন্ধান / প্রতিস্থাপনের সময় প্রতিস্থাপন করছেন, সেড ব্যবহার করুন:

sed 's/abc/XYZ/g' <infile >outfile

আপনি যদি জায়গায় জায়গায় ফাইলটি সম্পাদনা করতে চান (যেন কোনও সম্পাদককে ফাইলটি খোলার সাথে সাথে সম্পাদনা করে, তারপরে সংরক্ষণ করে) লাইন সম্পাদককে 'প্রাক্তন' সরবরাহের নির্দেশাবলী সরবরাহ করুন

echo "%s/abc/XYZ/g
w
q
" | ex file

প্রাক্তন পূর্ণ স্ক্রিন মোড ছাড়াই vi এর মতো। আপনি vi এর ':' প্রম্পটে এটিকে একই আদেশ দিতে পারেন।


33

আমি এই থ্রেডটি অন্যের মধ্যে পেয়েছি এবং আমি সম্মত হলাম এতে সর্বাধিক সম্পূর্ণ উত্তর রয়েছে যাতে আমি আমারও যুক্ত করছি:

  1. sedএবং edতাই দরকারী ... হাত দিয়ে। @ জন্নির এই কোডটি দেখুন:

    sed -i -e 's/abc/XYZ/g' /tmp/file.txt
  2. যখন আমার বিধিনিষেধটি শেল স্ক্রিপ্টে এটি ব্যবহার করা হয় তখন "অ্যাবিসি" বা "এক্সওয়াইজেড" এর জায়গায় কোনও ভেরিয়েবল ব্যবহার করা যায় না। BashFAQ কি আমি অন্তত বুঝতে সাথে একমত বলে মনে হয়। সুতরাং, আমি ব্যবহার করতে পারি না:

    x='abc'
    y='XYZ'
    sed -i -e 's/$x/$y/g' /tmp/file.txt
    #or,
    sed -i -e "s/$x/$y/g" /tmp/file.txt
    

    কিন্তু আমরা কি করতে পারি? হিসাবে, @ জননি বলেছেন একটি ব্যবহার করুন while read...তবে, দুর্ভাগ্যক্রমে এটি গল্পের শেষ নয়। নিম্নলিখিতগুলি আমার সাথে ভালভাবে কাজ করেছে:

    #edit user's virtual domain
    result=
    #if nullglob is set then, unset it temporarily
    is_nullglob=$( shopt -s | egrep -i '*nullglob' )
    if [[ is_nullglob ]]; then
       shopt -u nullglob
    fi
    while IFS= read -r line; do
       line="${line//'<servername>'/$server}"
       line="${line//'<serveralias>'/$alias}"
       line="${line//'<user>'/$user}"
       line="${line//'<group>'/$group}"
       result="$result""$line"'\n'
    done < $tmp
    echo -e $result > $tmp
    #if nullglob was set then, re-enable it
    if [[ is_nullglob ]]; then
       shopt -s nullglob
    fi
    #move user's virtual domain to Apache 2 domain directory
    ......
    
  3. যেহেতু কেউ দেখতে পাচ্ছে যে nullglobসেট করা আছে কিনা, এটিতে বিস্ময়করভাবে আচরণ করা যখন সেখানে স্ট্রিং থাকে *যেমন:

    <VirtualHost *:80>
     ServerName www.example.com
    

    যা হয়ে যায়

    <VirtualHost ServerName www.example.com

    এখানে শেষের কোন বন্ধনী নেই এবং অ্যাপাচি 2 এমনকি লোডও করতে পারে না।

  4. এই জাতীয় পার্সিংটি এক-হিট অনুসন্ধানের চেয়ে ধীরে ধীরে হওয়া উচিত এবং প্রতিস্থাপন করা উচিত তবে আপনি ইতিমধ্যে দেখেছেন যে একটি পার্স চক্রের বাইরে চারটি পৃথক অনুসন্ধান নিদর্শনগুলির জন্য চারটি ভেরিয়েবল রয়েছে।

সমস্যার প্রদত্ত অনুমানগুলি নিয়ে আমি সবচেয়ে উপযুক্ত সমাধানটি ভাবতে পারি।


12
আপনার (2) - এ আপনি করতে পারেন sed -e "s/$x/$y/", এবং এটি কার্যকর হবে। ডাবল উদ্ধৃতি নয়। ভেরিয়েবলের স্ট্রিংগুলিতে যদি বিশেষ অর্থ সহ অক্ষর থাকে তবে এটি গুরুতরভাবে বিভ্রান্ত হতে পারে। উদাহরণস্বরূপ যদি x = "/" বা x = "\" হয়। আপনি যখন এই সমস্যাগুলি আঘাত করেন, সম্ভবত এর অর্থ আপনার এই কাজের জন্য শেলটি ব্যবহার করার চেষ্টা করা বন্ধ করা উচিত।
পাতলা

হাই স্লিম, আমি দেখতে পাচ্ছি যে আপনিও পার্ল ব্যবহারের বিরোধী। আপনার সমাধান কি? কারণ আমি প্রকৃতপক্ষে একটি ফাইলের একটি গতিপথ পরিবর্তন করতে চাই, যার অর্থ আমার কাছে স্ট্রিংটিতে / প্রচুর আছে!
মাহদি

20

আপনি ব্যবহার করতে পারেন sed:

sed -i 's/abc/XYZ/gi' /tmp/file.txt

-iআপনি যদি নিশ্চিত হন যে পাঠ্যটি খুঁজে পাওয়া যায় abcনা ABCবা AbC, ইত্যাদি ক্ষেত্রে "উপেক্ষা কেস" ব্যবহার করুন Use

আপনি ব্যবহার করতে পারেন findএবং sedযদি আপনি নিজের ফাইলের নামটি জানেন না:

find ./ -type f -exec sed -i 's/abc/XYZ/gi' {} \;

সমস্ত পাইথন ফাইলগুলিতে সন্ধান করুন এবং প্রতিস্থাপন করুন:

find ./ -iname "*.py" -type f -exec sed -i 's/abc/XYZ/gi' {} \;

12

আপনি edইন-ফাইল অনুসন্ধান এবং প্রতিস্থাপন করতে কমান্ডটি ব্যবহার করতে পারেন :

# delete all lines matching foobar 
ed -s test.txt <<< $'g/foobar/d\nw' 

" স্ক্রিপ্টগুলির মাধ্যমে ফাইল সম্পাদনাed " তে আরও দেখুন ।


3
এই সমাধানটি জিএনইউ / ফ্রিবিএসডি (ম্যাক ওএসএক্স) অসঙ্গতিগুলি (বিপরীত sed -i <pattern> <filename>) থেকে স্বতন্ত্র । খুব সুন্দর!
পিটারিনো

11

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

file_contents=$(</tmp/file.txt)
echo "${file_contents//abc/XYZ}" > /tmp/file.txt

সম্পূর্ণ ফাইলের সামগ্রীগুলি লাইনব্র্যাক সহ এক দীর্ঘ স্ট্রিং হিসাবে বিবেচিত হবে।

এক্সওয়াইজেড একটি পরিবর্তনশীল উদাহরণস্বরূপ হতে পারে $replacementএবং এখানে সেড ব্যবহার না করার একটি সুবিধা হ'ল আপনার উদ্বেগের দরকার নেই যে অনুসন্ধান বা প্রতিস্থাপনের স্ট্রিংটিতে সেড প্যাটার্ন ডিলিমিটার অক্ষর থাকতে পারে (সাধারণত, তবে প্রয়োজনীয় নয়, /)। একটি অসুবিধা নিয়মিত প্রকাশ বা সেডের আরও পরিশীলিত অপারেশনগুলির কোনও ব্যবহার করতে সক্ষম হচ্ছে না।


ট্যাব অক্ষরের সাথে এটি ব্যবহারের জন্য কোনও টিপস? কোনও কারণে আমার স্ক্রিপ্টটি এই পদ্ধতিতে প্রচুর পালানোর মাধ্যমে সেড থেকে পরিবর্তনের পরে ট্যাবগুলির সাথে কিছুই খুঁজে পায় না।
ব্রায়ান হান্নে

2
আপনি যে স্ট্রিংটি প্রতিস্থাপন করছেন তাতে যদি আপনি কোনও ট্যাব রাখতে চান তবে আপনি বাশের "ডোলার্ডযুক্ত একক উদ্ধৃতি" বাক্য গঠন দিয়ে এটি করতে পারেন, তাই কোনও ট্যাব $ '\ t' দ্বারা উপস্থাপন করা হয়, এবং আপনি $ প্রতিধ্বনি 'ট্যাব' do করতে পারেন '\ t''separated'> টেস্টফিল; $ ফাইল_কন্টেন্টস = $ (<টেস্টফিলি); $ প্রতিধ্বনি "$ {ফাইল_কন্টেন্টস // $ '\ t' / ট্যাব}"; #Tabseparated `
johnraff


5

নিম্নলিখিত শেল কমান্ড ব্যবহার করে দেখুন:

find ./  -type f -name "file*.txt" | xargs sed -i -e 's/abc/xyz/g'

4
এটি "আমি কীভাবে ঘটনাক্রমে সমস্ত উপ-ডিরেক্টরিগুলির সমস্ত ফাইলও করব" এর একটি দুর্দান্ত উত্তর তবে এটি এখানে জিজ্ঞাসা করা হবে বলে মনে হয় না।
ট্রিপলি

এই বাক্য গঠনটি বিএসডি সংস্করণের পরিবর্তে sedব্যবহার করবে sed -i''না।
কেনারব

5

অ-ইন্টারেক্টিভ পদ্ধতিতে ফাইলটিতে পাঠ্য সম্পাদনা করতে আপনার ভিএম-এর মতো স্থানের পাঠ্য সম্পাদক প্রয়োজন।

কমান্ড লাইন থেকে এটি কীভাবে ব্যবহার করবেন তা এখানে সাধারণ উদাহরণ:

vim -esnc '%s/foo/bar/g|:wq' file.txt

এই সমতূল্য @slim উত্তর এর প্রাক্তন সম্পাদক যা মূলত একই জিনিস।

এখানে কয়েকটি exব্যবহারিক উদাহরণ দেওয়া হল।

টেক্সট প্রতিস্থাপন করা হচ্ছে fooসঙ্গে barফাইলে:

ex -s +%s/foo/bar/ge -cwq file.txt

একাধিক ফাইলের জন্য পূর্ববর্তী সাদা স্থান সরিয়ে ফেলা হচ্ছে:

ex +'bufdo!%s/\s\+$//e' -cxa *.txt

সমস্যার সমাধান (যখন টার্মিনাল আটকে থাকবে):

  • -V1ভার্বোজ বার্তাগুলি দেখাতে পরম যোগ করুন।
  • বাহিনী প্রস্থান: -cwq!

আরো দেখুন:


ইন্টারেক্টিভভাবে প্রতিস্থাপনগুলি করতে চেয়েছিলেন। সুতরাং "vim -esnc '% s / foo / bar / gc |: wq' file.txt" চেষ্টা করেছেন tried তবে টার্মিনালটি এখন আটকে আছে। বাশ শেলটি অদ্ভুত আচরণ না করে আমরা কীভাবে প্রতিস্থাপনগুলি ইন্টারেক্টিভভাবে করব।
ভিলেনেশভগুলি

ডিবাগ করতে, যুক্ত করতে -V1, জোর করে ছাড়তে, ব্যবহার করতে wq!
কেনরব

2

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

#!/bin/bash
python
filetosearch = '/home/ubuntu/ip_table.txt'
texttoreplace = 'tcp443'
texttoinsert = 'udp1194'

s = open(filetosearch).read()
s = s.replace(texttoreplace, texttoinsert)
f = open(filetosearch, 'w')
f.write(s)
f.close()
quit()

1

আপনি rpl কমান্ড ব্যবহার করতে পারেন। উদাহরণস্বরূপ আপনি পুরো পিএইচপি প্রকল্পে ডোমেনের নামটি পরিবর্তন করতে চান।

rpl -ivRpd -x'.php' 'old.domain.name' 'new.domain.name' ./path_to_your_project_folder/  

এটি কারণ পরিষ্কার নয়, তবে এটি খুব দ্রুত এবং দরকারী। :)

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