সেড - ফাইলে একটি শব্দের প্রথম কে দৃষ্টান্ত প্রতিস্থাপন করুন


24

আমি kএকটি শব্দের প্রথম প্রথম উদাহরণটি প্রতিস্থাপন করতে চাই ।

কিভাবে আমি এটি করতে পারব?

যেমন। বলুন ফাইলটিতে foo.txt'লিনাক্স' শব্দের 100 টি ঘটনা রয়েছে।

আমাকে কেবল প্রথম 50 টি ইভেন্টগুলি প্রতিস্থাপন করতে হবে।


1
আপনি এটি উল্লেখ করতে পারেন: unix.stackexchange.com/questions/21178/…
cuonglm

আপনার কি বিশেষভাবে সেড দরকার, না অন্য সরঞ্জাম গ্রহণযোগ্য? আপনার কি কমান্ড লাইনে কাজ করার দরকার আছে, বা কোনও পাঠ্য সম্পাদক গ্রহণযোগ্য?
খারাপসাপ

কমান্ড লাইনে যা কিছু কাজ করে তা গ্রহণযোগ্য।
নরেন্দ্র-চৌধুরী চৌদ্দ

উত্তর:


31

নীচের প্রথম বিভাগটি sedএকটি লাইনে প্রথম কে-উপস্থিতি পরিবর্তন করতে ব্যবহার করে বর্ণনা করে । দ্বিতীয় বিভাগটি কোনও লাইনে প্রদর্শিত হবে তা নির্বিশেষে কোনও ফাইলে কেবল প্রথম কে-উপস্থিতি পরিবর্তনের জন্য এই পদ্ধতির প্রসারিত করে।

লাইন-ভিত্তিক সমাধান

স্ট্যান্ডার্ড সেড সহ, একটি লাইনে শব্দের কে-থের উপস্থিতি প্রতিস্থাপন করার জন্য একটি কমান্ড রয়েছে। যদি k3 হয়, উদাহরণস্বরূপ:

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সমর্থন শব্দ সীমানা প্রতীক, \<এবং \>

ফাইল-ভিত্তিক সমাধান

আমরা সেডকে পুরো ফাইলটি পড়তে এবং তারপরে বিকল্পগুলি সম্পাদন করতে বলতে পারি। উদাহরণস্বরূপ, oldBSD- স্টাইলের সেড ব্যবহারের প্রথম তিনটি ঘটনাকে প্রতিস্থাপন করতে :

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ব্যাশ স্ট্রিংয়ে রাখা অসম্ভব তাই এটি সাধারণত একটি নিরাপদ অনুমান।


5
এটি কেবল রেখাগুলির জন্যই কাজ করে এবং প্রতিটি লাইনে প্রথম 4 টি ইভেন্ট পরিবর্তন করবে

1
@ মাইক্রোজার দুর্দান্ত ধারণা! উত্তর আপডেট হয়েছে।
1024

(1) আপনি জিএনইউ এবং নন-জিএনইউ সিড উল্লেখ করেছেন এবং পরামর্শ দিন 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'
জি-ম্যান

@ জি-ম্যান আপনাকে অনেক ধন্যবাদ! আমি উত্তর আপডেট করেছি।
1024

এটি এতই কুৎসিত
লুই ম্যাডডক্স

8

অজগর ব্যবহার করা হচ্ছে

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

"পুরানো" স্ট্রিংটি * পুরানো শব্দের আগে থাকলে প্রথমটি (সাব ব্যবহার করে) ভুল কাজ করে ; উদাহরণস্বরূপ, "বৃদ্ধকে কিছু সোনা দিন” "the" বৃদ্ধকে কিছু জড়িয়ে দিন Give "
জি-ম্যান বলেছেন 'রিইনস্টেট মনিকা'

@ জি-ম্যান হ্যাঁ আমি $iকিছুটা ভুলে গেছি , এটি সম্পাদিত হয়েছে, ধন্যবাদ :)

7

বলুন আপনি কেবল একটি স্ট্রিংয়ের প্রথম তিনটি প্রতিস্থাপন প্রতিস্থাপন করতে চান ...

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

4

পার্ল একটি সংক্ষিপ্ত বিকল্প:

perl -pe 'BEGIN{$n=3} 1 while s/old/new/ && ++$i < $n' your_file

আপনার পছন্দ অনুযায়ী `$ n $ এর মানটি পরিবর্তন করুন।

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

  • প্রতিটি লাইনের জন্য, এটি ( ) এর বিকল্প হিসাবে newরাখার চেষ্টা চালিয়ে যায় এবং যখনই পারে এটি পরিবর্তনশীল ( ) বৃদ্ধি করে increolds/old/new/$i++$i
  • এটি লাইনটিতে কাজ করে চলেছে ( 1 while ...যতক্ষণ না এটি $nসর্বমোট প্রতিস্থাপনের চেয়ে কম করেছে এবং এটি সেই লাইনে কমপক্ষে একটি প্রতিস্থাপন করতে পারে।

4

একটি শেল লুপ ব্যবহার করুন এবং 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

: এস // নতুন <সিআর> পাশাপাশি কাজ করা উচিত, কারণ একটি খালি রেজেক্স সর্বশেষ ব্যবহৃত অনুসন্ধানটিকে পুনরায় ব্যবহার করে
eike

3

একটি সহজ, তবে খুব দ্রুত সমাধান নয় /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 । নন-জিএনইউ সিডের জন্য এখানে ফাইলের প্রথম প্যাটার্নটি কীভাবে প্রতিস্থাপন করা যায় তা দেখুন ।


"পুরানো" কে "সাহসী" দিয়ে প্রতিস্থাপনের জন্য +1 সমস্যার কারণ হতে পারে।
জি-ম্যান বলছেন 'পুনরায় ইনস্টল করুন মনিকা'

2

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