আমি k
একটি শব্দের প্রথম প্রথম উদাহরণটি প্রতিস্থাপন করতে চাই ।
কিভাবে আমি এটি করতে পারব?
যেমন। বলুন ফাইলটিতে foo.txt
'লিনাক্স' শব্দের 100 টি ঘটনা রয়েছে।
আমাকে কেবল প্রথম 50 টি ইভেন্টগুলি প্রতিস্থাপন করতে হবে।
আমি k
একটি শব্দের প্রথম প্রথম উদাহরণটি প্রতিস্থাপন করতে চাই ।
কিভাবে আমি এটি করতে পারব?
যেমন। বলুন ফাইলটিতে foo.txt
'লিনাক্স' শব্দের 100 টি ঘটনা রয়েছে।
আমাকে কেবল প্রথম 50 টি ইভেন্টগুলি প্রতিস্থাপন করতে হবে।
উত্তর:
নীচের প্রথম বিভাগটি sed
একটি লাইনে প্রথম কে-উপস্থিতি পরিবর্তন করতে ব্যবহার করে বর্ণনা করে । দ্বিতীয় বিভাগটি কোনও লাইনে প্রদর্শিত হবে তা নির্বিশেষে কোনও ফাইলে কেবল প্রথম কে-উপস্থিতি পরিবর্তনের জন্য এই পদ্ধতির প্রসারিত করে।
স্ট্যান্ডার্ড সেড সহ, একটি লাইনে শব্দের কে-থের উপস্থিতি প্রতিস্থাপন করার জন্য একটি কমান্ড রয়েছে। যদি k
3 হয়, উদাহরণস্বরূপ:
sed 's/old/new/3'
বা, এর সাথে সমস্ত উপস্থিতি প্রতিস্থাপন করতে পারে:
sed 's/old/new/g'
এগুলির কোনওটিই আপনি চান না।
জিএনইউ sed
একটি এক্সটেনশান অফার করে যা কে-থের উপস্থিতি এবং তার পরে সমস্ত কিছু পরিবর্তন করবে। যদি কে 3 হয়, উদাহরণস্বরূপ:
sed 's/old/new/g3'
আপনি যা চান তা করার জন্য এগুলি একত্রিত করা যেতে পারে। প্রথম 3 টি ঘটনা পরিবর্তন করতে:
$ echo old old old old old | sed -E 's/\<old\>/\n/g4; s/\<old\>/new/g; s/\n/old/g'
new new new old old
\n
এখানে কোথায় দরকারী কারণ আমরা নিশ্চিত হতে পারি যে এটি কখনই কোনও লাইনে ঘটে না।
আমরা তিনটি sed
প্রতিস্থাপন কমান্ড ব্যবহার করি :
s/\<old\>/\n/g4
এই গনুহ এক্সটেনশন চতুর্থ এবং সব পরবর্তী ঘটনার প্রতিস্থাপন old
সঙ্গে \n
।
বর্ধিত রেজেক্স বৈশিষ্ট্যটি \<
কোনও শব্দের শুরুতে এবং শব্দের শেষের সাথে মেলে ব্যবহার করতে ব্যবহৃত হয় \>
। এটি নিশ্চিত করে যে কেবলমাত্র সম্পূর্ণ শব্দগুলির সাথে মিল রয়েছে। বর্ধিত রেজেক্সের -E
বিকল্পের প্রয়োজন sed
।
s/\<old\>/new/g
কেবল প্রথম তিনটি ঘটনা old
রয়ে গেছে এবং এটি তাদের সকলের সাথে প্রতিস্থাপন করে new
।
s/\n/old/g
চতুর্থ এবং বাকি সমস্ত ঘটনা প্রথম ধাপে old
প্রতিস্থাপন করা \n
হয়েছিল। এটি তাদেরকে তাদের মূল অবস্থায় ফিরিয়ে দেয়।
তাহলে গনুহ sed উপলব্ধ নয় এবং আপনার প্রথম 3 ঘটনার পরিবর্তন করতে চান old
করতে new
, তারপর তিন ব্যবহার s
কমান্ড:
$ echo old old old old old | sed -E -e 's/\<old\>/new/' -e 's/\<old\>/new/' -e 's/\<old\>/new/'
new new new old old
k
অল্প সংখ্যক হলে এটি ভাল কাজ করে তবে খারাপ থেকে বড় পর্যন্ত স্কেল করে k
।
যেহেতু কিছু নন-জিএনইউ সেড সেমিকোলনের সাথে একত্রিত কমান্ডগুলিকে সমর্থন করে না, তাই এখানে প্রতিটি কমান্ড তার নিজস্ব -e
বিকল্পের সাথে প্রবর্তিত হয় । এছাড়া তা যাচাই করতে আপনার প্রয়োজন হতে পারে sed
সমর্থন শব্দ সীমানা প্রতীক, \<
এবং \>
।
আমরা সেডকে পুরো ফাইলটি পড়তে এবং তারপরে বিকল্পগুলি সম্পাদন করতে বলতে পারি। উদাহরণস্বরূপ, old
BSD- স্টাইলের সেড ব্যবহারের প্রথম তিনটি ঘটনাকে প্রতিস্থাপন করতে :
sed -E -e 'H;1h;$!d;x' -e 's/\<old\>/new/' -e 's/\<old\>/new/' -e 's/\<old\>/new/'
সেড কমান্ডগুলি H;1h;$!d;x
পুরো ফাইলটি পড়ে।
কারণ উপরেরগুলি কোনও জিএনইউ এক্সটেনশন ব্যবহার করে না, এটি বিএসডি (ওএসএক্স) সেডে কাজ করা উচিত। দ্রষ্টব্য, চিন্তাভাবনা, এই পদ্ধতির জন্য এমন একটি দরকার sed
যা দীর্ঘ লাইন পরিচালনা করতে পারে। জিএনইউ ঠিক sed
থাকতে হবে। যাদের নন-জিএনইউ সংস্করণ ব্যবহার করছে sed
তাদের লম্বা লাইনগুলি হ্যান্ডেল করার দক্ষতাটি পরীক্ষা করা উচিত।
একটি জিএনইউ সেডের সাহায্যে, আমরা প্রথম তিনটি ঘটনাকে প্রতিস্থাপনের জন্য g
উপরে বর্ণিত কৌশলটি আরও ব্যবহার করতে পারি , তবে \n
প্রতিস্থাপনের সাথে \x00
:
sed -E -e 'H;1h;$!d;x; s/\<old\>/\x00/g4; s/\<old\>/new/g; s/\x00/old/g'
এই পদ্ধতির আকারটি পাশাপাশি k
আকারে বড় হয়। এটি ধরে নেওয়া হয়, যদিও \x00
এটি আপনার মূল স্ট্রিংটিতে নেই। যেহেতু চরিত্রটিকে \x00
ব্যাশ স্ট্রিংয়ে রাখা অসম্ভব তাই এটি সাধারণত একটি নিরাপদ অনুমান।
tr '\n' '|' < input_file | sed …
। তবে, অবশ্যই, এটি পুরো ইনপুটটিকে এক লাইনে রূপান্তর করে এবং কিছু নন-জিএনইউ সেড ইচ্ছামত দীর্ঘ লাইন পরিচালনা করতে পারে না। (২) আপনি বলেছেন, "… উপরে, উদ্ধৃত স্ট্রিংটি '|'
কোনও অক্ষর বা অক্ষরের স্ট্রিং দ্বারা প্রতিস্থাপন করা উচিত ..." তবে আপনি tr
কোনও অক্ষর (দৈর্ঘ্যের> 1) দ্বারা প্রতিস্থাপন করতে পারবেন না । (3) আপনার শেষ উদাহরণে, আপনি বলেছেন -e 's/\<old\>/new/' -e 's/\<old\>/w/' | tr '\000' '\n'\>/new
। এটি একটি টাইপ বলে মনে হচ্ছে -e 's/\<old\>/new/' -e 's/\<old\>/new/' -e 's/\<old\>/new/' | tr '\000' '\n'
।
Awk কমান্ডগুলি শব্দের প্রথম এন উপস্থিতিগুলি প্রতিস্থাপনের সাথে প্রতিস্থাপন করতে ব্যবহার করা যেতে পারে।
শব্দটি সম্পূর্ণ মিল থাকলে কমান্ডগুলি কেবল প্রতিস্থাপন করবে।
নীচের উদাহরণগুলিতে, আমি প্রথম 27
ঘটনার old
সাথে প্রতিস্থাপন করছিnew
সাব ব্যবহার
awk '{for(i=1;i<=NF;i++){if(x<27&&$i=="old"){x++;sub("old","new",$i)}}}1' file
এই কমান্ডটি প্রতিটি ক্ষেত্রের সাথে মেলে না যাওয়া পর্যন্ত লুপ করে
old
, এটি কাউন্টারটি 27 এর নীচে, ইনক্রিমেন্টগুলি এবং লাইনে প্রথম ম্যাচটি বিকল্প হিসাবে পরীক্ষা করে। তারপরে পরবর্তী ক্ষেত্র / লাইনে চলে আসে এবং পুনরাবৃত্তি করে।
ক্ষেত্রটি ম্যানুয়ালি প্রতিস্থাপন
awk '{for(i=1;i<=NF;i++)if(x<27&&$i=="old"&&$i="new")x++}1' file
কমান্ড অনুরূপ আগে কিন্তু এটি ইতিমধ্যেই একটি চিহ্নিতকারী যা ক্ষেত্র তে এটি আপ হয় হয়েছে
($i)
, এটা শুধু থেকে মাঠের মান পরিবর্তনold
করতেnew
।
আগে একটি পরীক্ষা করা
awk '/old/&&x<27{for(i=1;i<=NF;i++)if(x<27&&$i=="old"&&$i="new")x++}1' file
লাইনটি পুরানো এবং কাউন্টারটি 27 এর নীচে রয়েছে তা পরীক্ষা করা
SHOULD
একটি ছোট গতি বাড়িয়ে দেয় কারণ এটি মিথ্যা হলে লাইনগুলি প্রসেস করে না।
ফলাফল
যেমন
old bold old old old
old old nold old old
old old old gold old
old gold gold old old
old old old man old old
old old old old dog old
old old old old say old
old old old old blah old
থেকে
new bold new new new
new new nold new new
new new new gold new
new gold gold new new
new new new man new new
new new new new dog new
new new old old say old
old old old old blah old
বলুন আপনি কেবল একটি স্ট্রিংয়ের প্রথম তিনটি প্রতিস্থাপন প্রতিস্থাপন করতে চান ...
seq 11 100 311 |
sed -e 's/1/\
&/g' \ #s/match string/\nmatch string/globally
-e :t \ #define label t
-e '/\n/{ x' \ #newlines must match - exchange hold and pattern spaces
-e '/.\{3\}/!{' \ #if not 3 characters in hold space do
-e 's/$/./' \ #add a new char to hold space
-e x \ #exchange hold/pattern spaces again
-e 's/\n1/2/' \ #replace first occurring '\n1' string w/ '2' string
-e 'b t' \ #branch back to label t
-e '};x' \ #end match function; exchange hold/pattern spaces
-e '};s/\n//g' #end match function; remove all newline characters
দ্রষ্টব্য: উপরেরটি সম্ভবত এম্বেড করা মন্তব্যে
... বা আমার উদাহরণস্বরূপ, '1' এর সাথে কাজ করবে না ...
22
211
211
311
সেখানে আমি দুটি উল্লেখযোগ্য কৌশল ব্যবহার করি। প্রথম স্থানে 1
একটি লাইনের প্রতিটি সংস্থান প্রতিস্থাপন করা হয় \n1
। এইভাবে, আমি পরবর্তী সময়ে পুনরাবৃত্ত প্রতিস্থাপনগুলি করি, আমি নিশ্চিত হতে পারি যে আমার প্রতিস্থাপনের স্ট্রিংয়ে আমার প্রতিস্থাপনের স্ট্রিং থাকলে দু'বারের উপস্থিতিটি প্রতিস্থাপন করা সম্ভব হবে না । উদাহরণস্বরূপ, আমি যদি এটির he
সাথে প্রতিস্থাপন করি তবে hey
এটি এখনও কাজ করবে।
আমি এই মত:
s/1/\
&/g
দ্বিতীয়ত, আমি h
প্রতিটি ঘটনার জন্য পুরানো জায়গায় একটি অক্ষর যুক্ত করে প্রতিস্থাপনগুলি গণনা করছি । একবার আমি তিন এ পৌঁছানোর পরে আর ঘটবে না। আপনি যদি এটি আপনার ডেটাতে প্রয়োগ করেন \{3\}
এবং আপনার সম্পূর্ণ প্রতিস্থাপন এবং /\n1/
ঠিকানাগুলি যা আপনি প্রতিস্থাপন করতে চান তার পরিবর্তে, আপনার ইচ্ছামত কেবল প্রতিস্থাপন করা উচিত।
আমি কেবল -e
পাঠযোগ্যতার জন্য সমস্ত স্টাফ করেছি। এটি পোস্ট করা যেতে পারে:
nl='
'; sed "s/1/\\$nl&/g;:t${nl}/\n/{x;/.\{3\}/!{${nl}s/$/./;x;s/\n1/2/;bt$nl};x$nl};s/\n//g"
এবং ডাব্লু / জিএনইউ sed
:
sed 's/1/\n&/g;:t;/\n/{x;/.\{3\}/!{s/$/./;x;s/\n1/2/;bt};x};s/\n//g'
sed
লাইন-ওরিয়েন্টেড এটিও মনে রাখবেন - এটি পুরো ফাইলটিতে পড়ে না এবং এরপরে আবার লুপ করার চেষ্টা করে না যেমন অন্যান্য সম্পাদকদের ক্ষেত্রে প্রায়শই ঘটে। sed
সহজ এবং দক্ষ। এটি বলেছিল, নীচের মতো কিছু করা প্রায়শই সুবিধাজনক:
এখানে একটি সামান্য শেল ফাংশন রয়েছে যা এটি একটি সাধারণ সম্পাদিত কমান্ডের মধ্যে বান্ডিল করে:
firstn() { sed "s/$2/\
&/g;:t
/\n/{x
/.\{$(($1))"',\}/!{
s/$/./; x; s/\n'"$2/$3"'/
b t
};x
};s/\n//g'; }
সুতরাং যে আমি করতে পারেন:
seq 11 100 311 | firstn 7 1 5
...এবং পেতে...
55
555
255
311
... অথবা ...
seq 10 1 25 | firstn 6 '\(.\)\([1-5]\)' '\15\2'
... পেতে ...
10
151
152
153
154
155
16
17
18
19
20
251
22
23
24
25
... বা, আপনার উদাহরণের সাথে মেলে ধরার জন্য (প্রস্থের একটি ছোট ক্রমে) :
yes linux | head -n 10 | firstn 5 linux 'linux is an os kernel'
linux is an os kernel
linux is an os kernel
linux is an os kernel
linux is an os kernel
linux is an os kernel
linux
linux
linux
linux
linux
পার্ল একটি সংক্ষিপ্ত বিকল্প:
perl -pe 'BEGIN{$n=3} 1 while s/old/new/ && ++$i < $n' your_file
আপনার পছন্দ অনুযায়ী `$ n $ এর মানটি পরিবর্তন করুন।
কিভাবে এটা কাজ করে:
new
রাখার চেষ্টা চালিয়ে যায় এবং যখনই পারে এটি পরিবর্তনশীল ( ) বৃদ্ধি করে increold
s/old/new/
$i
++$i
1 while ...
যতক্ষণ না এটি $n
সর্বমোট প্রতিস্থাপনের চেয়ে কম করেছে এবং এটি সেই লাইনে কমপক্ষে একটি প্রতিস্থাপন করতে পারে।একটি শেল লুপ ব্যবহার করুন এবং ex
!
{ for i in {1..50}; do printf %s\\n '0/old/s//new/'; done; echo x;} | ex file.txt
হ্যাঁ, এটি কিছুটা বোকা।
;)
দ্রষ্টব্য: old
ফাইলটিতে 50 টিরও কম উদাহরণ থাকলে এটি ব্যর্থ হতে পারে । (আমি এটি পরীক্ষা করে দেখিনি।) যদি তাই হয় তবে এটি ফাইলটি অবিস্মরণীয় করে রেখে যাবে।
আরও ভাল, Vim ব্যবহার করুন।
vim file.txt
qqgg/old<CR>:s/old/new/<CR>q49@q
:x
ব্যাখ্যা:
q # Start recording macro
q # Into register q
gg # Go to start of file
/old<CR> # Go to first instance of 'old'
:s/old/new/<CR> # Change it to 'new'
q # Stop recording
49@q # Replay macro 49 times
:x # Save and exit
একটি সহজ, তবে খুব দ্রুত সমাধান নয় /programming/148451/how-to-use-sed-to-replace-only-the-first-occurrence-in-a এ বর্ণিত আদেশগুলি লুপ করা -file
for i in $(seq 50) ; do sed -i -e "0,/oldword/s//newword/" file.txt ; done
এই বিশেষ sed কমান্ড সম্ভবত গনুহ sed এবং যদি শুধু জন্য কাজ করে newword অংশ নয় oldword । নন-জিএনইউ সিডের জন্য এখানে ফাইলের প্রথম প্যাটার্নটি কীভাবে প্রতিস্থাপন করা যায় তা দেখুন ।
গনুহ সঙ্গে awk
আপনার রেকর্ড করা বিভাজক সেট করতে পারেন RS
করার কথা প্রতিস্থাপিত হতে শব্দ সীমানা দ্বারা সীমায়িত। তারপরে এটি k
বাকী অংশের জন্য মূল রেকর্ড পৃথককে ধরে রেখে প্রথম রেকর্ডের জন্য প্রতিস্থাপন শব্দের আউটপুটে রেকর্ড বিভাজক স্থাপনের ঘটনা is
awk -vRS='\\ylinux\\y' -vreplacement=unix -vlimit=50 \
'{printf "%s%s", $0, NR <= limit? replacement: RT}' file
অথবা
awk -vRS='\\ylinux\\y' -vreplacement=unix -vlimit=50 \
'{printf "%s%s", $0, limit--? replacement: RT}' file