সেড: একক-লাইন ইনপুটটিতে ব্যর্থ না হয়ে পুরো ফাইলটি প্যাটার্ন স্পেসে পড়ুন


9

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

sed ':a;N;$!ba; [commands...]'

তবে ইনপুটটিতে কেবলমাত্র একটি লাইন থাকে তা ব্যর্থ হয়।

উদাহরণস্বরূপ, দুটি লাইন ইনপুট সহ, প্রতিটি লাইন সাবস্টিটিউশন কমান্ড সাপেক্ষে:

$ echo $'abc\ncat' | sed ':a;N;$!ba; s/a/xxx/g'
xxxbc
cxxxt

তবে, একক লাইন ইনপুট সহ, কোনও প্রতিস্থাপন করা হয় না:

$ echo 'abc' | sed ':a;N;$!ba; s/a/xxx/g'
abc

কীভাবে একজন sedএকবারে সমস্ত ইনপুট পড়ার জন্য কোনও আদেশ লিখবে এবং এই সমস্যাটি না ঘটে?


আমি আপনার প্রশ্নটি সম্পাদনা করেছি যাতে এটিতে একটি আসল প্রশ্ন থাকে। আপনি চাইলে অন্যান্য উত্তরের জন্য অপেক্ষা করতে পারেন তবে শেষ পর্যন্ত গৃহীত হিসাবে সেরা উত্তরটি চিহ্নিত করুন (উত্তরের বামে পাইপ বোতামটি ডানদিকে উপরে ডাউন তীর বোতামের নীচে দেখুন)।
1024

@ জন 1024 ধন্যবাদ, একটি উদাহরণ পেয়ে ভাল। এই ধরণের জিনিস খুঁজে পাওয়া আমাকে মনে করিয়ে দেয় যে "সবকিছুই ভুল" তবে আমি আনন্দিত যে আমাদের মধ্যে কিছু লোক হাল ছাড়েনি। :}
ডিকটিয়ার

2
তৃতীয় বিকল্প আছে! GNU এর sed -zবিকল্পটি ব্যবহার করুন । যদি আপনার ফাইলটি শূন্য না হয় তবে এটি ফাইলের শেষ অবধি পড়বে! থেকে এই পাওয়া গেছে: stackoverflow.com/a/30049447/582917
CMCDragonkai

উত্তর:


13

প্যাটার্ন স্পেসে পুরো ফাইলটি পড়া ভুল হতে পারে এমন সমস্ত কারণ রয়েছে। শেষ লাইনের চারপাশে থাকা প্রশ্নের যুক্তিযুক্ত সমস্যাটি একটি সাধারণ বিষয়। এটি sedএর লাইন চক্রের সাথে সম্পর্কিত - যখন আর কোনও লাইন থাকে না এবং sedইওএফটির মুখোমুখি হয় না - এটি প্রক্রিয়াকরণ ত্যাগ করে। এবং তাই আপনি যদি সর্বশেষ লাইনে থাকেন এবং আপনি sedঅন্যটি পেতে নির্দেশ দেন তবে এটি ঠিক সেখানে থামতে চলেছে এবং আরও কিছু করবে না।

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

অনেকগুলি অনুরূপ সরঞ্জাম রয়েছে যা পুরো ফাইল ব্লকগুলি হ্যান্ডেল করার জন্য আরও ভাল সজ্জিত। edএবং ex, উদাহরণস্বরূপ, যা করতে পারে তার অনেক কিছুই sedকরতে পারে এবং একই রকম সিনট্যাক্স সহ - এবং আরও অনেক কিছু - বরং কেবলমাত্র একটি ইনপুট স্ট্রিমে কাজ করার পরিবর্তে এটিকে আউটপুটে রূপান্তরিত করার পরিবর্তে sedতারা ফাইল-সিস্টেমে অস্থায়ী ব্যাকআপ ফাইলগুলিও বজায় রাখে । তাদের কাজটি প্রয়োজন অনুযায়ী ডিস্কে বাফার করা হয় এবং তারা ফাইলের শেষে হঠাৎ ছেড়ে যায় না (এবং বাফার স্ট্রেনে খুব কম প্রায়ই প্ররোচিত হয়) । তদুপরি তারা অনেকগুলি কার্যকর ফাংশন সরবরাহ করে যা sedনা - এমন একটি সাজানোর যা কেবল স্ট্রিমের প্রসঙ্গে বোঝায় না - যেমন লাইন চিহ্ন, পূর্বাবস্থায় নামকরণ করা বাফারস, যোগ দিন এবং আরও অনেক কিছু।

sedএর প্রাথমিক শক্তি হ'ল এটি দ্রুত পড়ার সাথে সাথে - দ্রুত, দক্ষতার সাথে এবং প্রবাহে প্রক্রিয়াকরণের দক্ষতা। যখন আপনি একটি ফাইল গবগব করে খাওয়া আপনি যে বর্জন করা এবং আপনি শেষ লাইন সমস্যা উল্লেখ মত প্রান্ত ক্ষেত্রে অসুবিধা মধ্যে চালানোর জন্য, এবং overruns বাফার ঝোঁক, এবং অতল কর্মক্ষমতা - তথ্য এটা parses যেমন দৈর্ঘ্য কোন RegExp ইঞ্জিন এর প্রক্রিয়াকরণের বৃদ্ধি যখন ম্যাচ enumerating তাত্পর্যপূর্ণভাবে বৃদ্ধি পায়

শেষ পয়েন্টটি সম্পর্কে, যাইহোক: আমি যখন বুঝতে পারি উদাহরণস্বরূপ s/a/A/gসম্ভবত একটি নিখুঁত উদাহরণ এবং সম্ভবত আপনি যে ইনপুটটিতে সংগ্রহ করতে চান এটি প্রকৃত স্ক্রিপ্ট নয়, তবে নিজেকে নিজের সাথে পরিচয় করিয়ে দেওয়ার জন্য আপনি এটি উপযুক্ত হিসাবে খুঁজে পেতে পারেন y///। আপনি যদি নিজেকে প্রায়শই gনিবিড়ভাবে অন্য একটির চরিত্রের পরিবর্তে দেখতে পান তবে আপনার পক্ষে এটি yখুব কার্যকর হতে পারে। এটি একটি প্রতিস্থাপনের বিপরীতে রূপান্তর এবং এটি একটি রেজিপ্সকে বোঝায় না তত দ্রুত। এই পরবর্তী পয়েন্টটি খালি //ঠিকানাগুলি সংরক্ষণ এবং পুনরাবৃত্তি করার চেষ্টা করার সময়ও এটি কার্যকর করতে পারে কারণ এটি তাদের প্রভাবিত করে না তবে তাদের দ্বারা প্রভাবিত হতে পারে। যাই হোক, y/a/A/একই পৌঁছনোর একটি সহজ উপায় - এবং অদলবদল ভাল মত যতটা সম্ভব আছেন:y/aA/Aa/ যা একে অপরের জন্য একটি রেখার মতো সমস্ত উপরের / ছোট হাতের আদান প্রদান করে।

আপনার এও লক্ষ্য করা উচিত যে আপনি যে আচরণটি বর্ণনা করেছেন তা বাস্তবে যা হওয়ার কথা তা ঠিক নয়।

থেকে গনুহ এর info sedমধ্যে সাধারণভাবে রিপোর্ট বাগ অধ্যায়:

  • N শেষ লাইনে কমান্ড

    • কোনও ফাইলের শেষ লাইনে কমান্ড জারি করা sedহলে কোনও প্রিন্ট না করে প্রস্থানের বেশিরভাগ সংস্করণ N। জিএনইউ sedপ্রস্থান করার আগে প্যাটার্ন স্পেস প্রিন্ট করে তবে অবশ্যই -nকমান্ড স্যুইচ নির্দিষ্ট না করা থাকে। এই পছন্দটি ডিজাইন দ্বারা।

    • উদাহরণস্বরূপ, এর sed N foo barfoo এর সমান বা একটি বিজোড় সংখ্যক রেখার উপর নির্ভর করে। বা, কোনও প্যাটার্ন ম্যাচের পরে পরবর্তী কয়েকটি লাইন পড়তে কোনও স্ক্রিপ্ট লেখার সময়, traditionalতিহ্যবাহী বাস্তবায়নগুলি sedআপনাকে ন্যায়বিচারের /foo/{ $!N; $!N; $!N; $!N; $!N; $!N; $!N; $!N; $!N }পরিবর্তে কিছু লিখতে বাধ্য করে /foo/{ N;N;N;N;N;N;N;N;N; }

    • যে কোনও ক্ষেত্রে, সবচেয়ে সহজ কাজটি হ'ল .তিহ্যবাহী $d;Nআচরণের উপর নির্ভর করে এমন স্ক্রিপ্টগুলিতে ব্যবহার করা বা POSIXLY_CORRECTভেরিয়েবলটিকে একটি শূন্য ন্যূনতম মান হিসাবে সেট করা।

POSIXLY_CORRECTএনভায়রনমেন্ট ভেরিয়েবল উল্লেখ করা হয় কারণ POSIX নির্দিষ্ট করে যে যদি sedএনকাউন্টার ফাইলের শেষে যখন প্রয়াস একটি Nএটা আউটপুট না করে প্রস্থান করা উচিত, কিন্তু গনুহ সংস্করণ ইচ্ছাকৃতভাবে এই ক্ষেত্রে মান বিরতি। আরও মনে রাখবেন যে আচরণটি যেমন ধরে নেওয়া যায় যে অনুমানের উপরেও ন্যায়বিচার করা হয় ত্রুটি কেস স্ট্রিম-এডিটিংয়ের একটি - একটি সম্পূর্ণ ফাইলকে মেমোরিতে স্লাপ করে না।

মান সংজ্ঞায়িত Nএর আচরণ এইভাবে:

  • N

    • আসল উপাদানটি মূল উপাদান থেকে পৃথক করতে \nএম্বেডড \nইওলাইনটি ব্যবহার করে, নিদর্শন জায়গাতে কম ইনপুট পরবর্তী লাইন যুক্ত করুন its নোট করুন যে বর্তমান লাইন নম্বর পরিবর্তন হয়।

    • যদি পরবর্তী কোনও লাইন ইনপুট পাওয়া না যায় তবে Nকমান্ড ক্রিয়াটি স্ক্রিপ্টের শেষে শাখা করে কোনও নতুন চক্র শুরু না করে বা নকশার স্থানটি স্ট্যান্ডার্ড আউটপুটে অনুলিপি না করে ছাড়বে।

এই নোটটিতে, প্রশ্নটিতে আরও কিছু জিএনইউ-ইস্মগুলি প্রদর্শিত হয়েছে - বিশেষত :লেবেল, bরাঞ্চ এবং {ফাংশন-প্রসঙ্গের বন্ধনীগুলির ব্যবহার }। থাম্বের নিয়ম হিসাবে যেকোন sedকমান্ড যা একটি স্বেচ্ছাসেবী পরামিতি গ্রহণ \nকরে তা স্ক্রিপ্টের একটি ই- লাইনটিতে সীমানা বোঝা যায় । সুতরাং আদেশগুলি ...

:arbitrary_label_name; ...
b to_arbitrary_label_name; ...
//{ do arbitrary list of commands } ...

... এগুলি sedপড়ার বাস্তবায়নের উপর নির্ভর করে ভ্রান্তভাবে সম্পাদন করার সম্ভাবনা রয়েছে । বহনযোগ্যভাবে সেগুলি লেখা উচিত:

...;:arbitrary_label_name
...;b to_arbitrary_label_name
//{ do arbitrary list of commands
}

একই জন্য কথা সত্য r, w, t, a, i, এবং c (এবং সম্ভবত আরো কয়েকটি যে আমি মুহূর্তে বিস্মরণ করছি) । প্রায় প্রতিটি ক্ষেত্রে এগুলিও লিখিত হতে পারে:

sed -e :arbitrary_label_name -e b\ to_arbitary_label_name -e \
    "//{ do arbitrary list of commands" -e \}

... যেখানে নতুন -eএক্সিকিউশন স্টেটমেন্টটি \nইভলাইন ডিলিমিটারের জন্য দাঁড়িয়েছে । GNU infoপাঠ্যটি যেখানে প্রস্তাবিত সেখানে একটি traditional sedতিহ্যবাহী বাস্তবায়ন আপনাকে বাধ্য করতে বাধ্য করবে :

/foo/{ $!N; $!N; $!N; $!N; $!N; $!N; $!N; $!N; $!N }

... বরং এটি হওয়া উচিত ...

/foo/{ $!N; $!N; $!N; $!N; $!N; $!N; $!N; $!N; $!N
}

... অবশ্যই এটি সত্য নয়। স্ক্রিপ্টটি সেভাবে লেখা একটু নির্বোধ। এটি করার আরও অনেক সহজ উপায় রয়েছে, যেমন:

printf %s\\n foo . . . . . . |
sed -ne 'H;/foo/h;x;//s/\n/&/3p;tnd
         //!g;x;$!d;:nd' -e 'l;$a\' \
     -e 'this is the last line' 

... যা প্রিন্ট করে:

foo
.
.
.
foo\n.\n.\n.$
.$
this is the last line

... কারণ tএস্ট কমান্ড - বেশিরভাগ sedকমান্ডের মতো - তার রিটার্ন রেজিস্ট্রেশন রিফ্রেশ করার জন্য লাইন চক্রের উপর নির্ভর করে এবং এখানে লাইন চক্রটি বেশিরভাগ কাজ করার অনুমতি পায়। আপনি যখন কোনও ফাইল স্লাপ করেন তখন এটি আপনার করা অন্য ট্রেড অফ - লাইন চক্রটি আর কখনও রিফ্রেশ হয় না, এবং অনেকগুলি পরীক্ষা অস্বাভাবিক আচরণ করবে।

উপরের কমান্ডটি অতিরিক্ত পৌঁছানোর ইনপুট ঝুঁকিপূর্ণ নয় কারণ এটি কী পড়বে তা যাচাই করে তা যাচাই করতে কেবল কিছু সাধারণ পরীক্ষা করে। সঙ্গে Hপুরাতন সব লাইন হোল্ড স্থান থেকে যোগ করা থাকে তবে যদি একটি লাইন মিলে যায় /foo/এটা মুছে ফেলা হয় hপুরাতন স্থান। বাফারগুলি পরবর্তী সময়ে xপরিবর্তিত হবে এবং s///বাফারের সামগ্রীগুলি //শেষ প্যাটার্নটির সাথে মিলে গেলে একটি শর্তসাপেক্ষ দাবির চেষ্টা করা হয় । অন্য কথায় //s/\n/&/3pনিজের সাথে হোল্ড স্পেসে তৃতীয় নিউলাইনটি প্রতিস্থাপনের চেষ্টা করে এবং বর্তমানে যদি স্থানটি মেলে তবে ফলগুলি মুদ্রণ করার চেষ্টা করে /foo/। যে tests সফল করার স্ক্রিপ্ট শাখা nOT delete ট্যাগ - যা আছে lওক্ এবং স্ক্রিপ্ট আপ গোপন।

ক্ষেত্রে যে উভয় ইন /foo/ও তৃতীয় সম্পর্কে newline হোল্ড স্থান একসঙ্গে মিলেছে করা যাবে না যদিও, তারপর //!gবাফার ওপর ওভাররাইট করা হবে /foo/মেলে না, বা, যদি এটা মিলেছে হয়, এটি যদি একটি বাফার মুছে ফেলা হবে \newline মেলে না (যার ফলে প্রতিস্থাপন /foo/সঙ্গে নিজেই) । এই সামান্য সূক্ষ্ম পরীক্ষাটি বাফারটিকে অকারণে দীর্ঘায়িতভাবে পূরণ করা থেকে বিরত রাখে /foo/এবং প্রক্রিয়াটি নিখরচায় থাকার বিষয়টি নিশ্চিত করে কারণ ইনপুটটি পাইল না। কোনও /foo/বা //s/\n/&/3pব্যর্থ ক্ষেত্রে অনুসরণ করে বাফারগুলি আবার অদলবদল হয় এবং প্রতিটি লাইন কিন্তু শেষটি সেখানে মুছে ফেলা হয়।

এটি সর্বশেষ - শেষ লাইন $!d- কীভাবে sedসহজেই একাধিক কেসগুলি পরিচালনা করতে শীর্ষ-ডাউন স্ক্রিপ্ট তৈরি করা যায় তার একটি সহজ বুদ্ধি । যখন আপনার সাধারণ পদ্ধতিটি সর্বাধিক সাধারণ দিয়ে শুরু হওয়া এবং সুনির্দিষ্ট নির্দিষ্ট প্রান্তের দিকে কাজ করা অনাকাঙ্ক্ষিত কেসগুলি ছাঁটাই করা হয় তখন সহজেই পরিচালনা করা যায় কারণ এগুলি কেবল আপনার অন্যান্য প্রয়োজনীয় ডেটা সহ স্ক্রিপ্টের শেষ প্রান্তে পড়ার অনুমতি দেওয়া হয় when এগুলি সমস্ত আপনি আবশ্যক কেবল আপনার পছন্দসই ডেটা দিয়ে। যদিও বন্ধ লুপের বাইরে এ জাতীয় প্রান্তের মামলাগুলি পাওয়া খুব বেশি কঠিন হতে পারে, যদিও।

এবং তাই এখানে আমার শেষ কথাটি বলতে হবে: যদি আপনাকে অবশ্যই একটি সম্পূর্ণ ফাইল টানতে হয় তবে আপনার জন্য এটি করার জন্য লাইন চক্রের উপর নির্ভর করে আপনি কিছুটা কম কাজ করতে দাঁড়াতে পারেন। সাধারণত আপনি ব্যবহার করেন NEXT এবং nজন্য EXT lookahead - কারণ তারা আগাম এগিয়ে লাইন চক্রের। একটি লুপের মধ্যে অপ্রয়োজনীয়ভাবে একটি বদ্ধ লুপটি প্রয়োগ করার পরিবর্তে - যেমন sedলাইন চক্রটি যাইহোক কেবল একটি সরল পঠনের লুপ - যদি আপনার উদ্দেশ্য কেবল নির্বিচারে ইনপুট সংগ্রহ করা হয়, তবে সম্ভবত এটি করা আরও সহজ:

sed 'H;1h;$!d;x;...'

... যা পুরো ফাইলটি সংগ্রহ করবে বা চেষ্টা করার চেষ্টা করবে।


Nসর্বশেষ লাইন আচরণ সম্পর্কে একটি পক্ষের নোট ...

যখন আমি টুলস পরীক্ষা আমার কাছে প্রাপ্তিসাধ্য না থাকে, যে বিবেচনা Nযখন পড়া ও ইন-জায়গা সম্পাদনা ভিন্নভাবে আচরণ করবে ফাইলটি সম্পাদিত পরবর্তী readthrough জন্য স্ক্রিপ্ট ফাইল।


1
নিঃশর্তকে Hপ্রথমে রাখা সুন্দর।
jthill

@ মিকসার্ভ আপনার ইনপুট জন্য ধন্যবাদ। আমি লাইন চক্র রাখার সম্ভাব্য সুবিধা দেখতে পাচ্ছি, তবে এটি কীভাবে কম কাজ করবে?
ডিকটিয়ার

@ ডিক্টির ভাল, সিন্টেক্সটি কিছু শর্টকাট নিয়েছে :a;$!{N;ba}যেমন আমি উপরে উল্লেখ করেছি - আপনি অপরিচিত সিস্টেমে রিজেক্সপ চালানোর চেষ্টা করলে দীর্ঘমেয়াদে স্ট্যান্ডার্ড ফর্ম ব্যবহার করা সহজ। তবে এটি আসলে আমি বোঝাতে চাইনি: আপনি একটি বদ্ধ লুপটি প্রয়োগ করেন - আপনি যখন চান তার পরিবর্তে শাখা-প্রশাখা - অযাচিত তথ্য ছাঁটাই করে - এবং চক্রটি ঘটতে দিয়ে তার মধ্য দিয়ে যেতে পারবেন না। এটি টপ-ডাউন জিনিসটির মতো - সবকিছুই sedএটি সবেমাত্র কী করেছে তার প্রত্যক্ষ ফলাফল। হতে পারে আপনি এটিকে অন্যভাবে দেখেন - তবে আপনি যদি এটি চেষ্টা করেন তবে স্ক্রিপ্টটি সহজেই পাওয়া যাবে।
মাইকসার্ভ

11

এটি ব্যর্থ হয় কারণ Nকমান্ডটি প্যাটার্ন ম্যাচের আগে $!(শেষ লাইন নয়) আসে এবং কোনও কাজ করার আগে সেড প্রস্থান করে:

এন

প্যাটার্ন স্পেসে একটি নতুন লাইন যুক্ত করুন, তারপরে প্যাটার্ন স্পেসে ইনপুটটির পরবর্তী লাইনটি যুক্ত করুন। যদি আরও ইনপুট না থাকে তবে সেড আরও কোনও কমান্ড প্রক্রিয়াকরণ ছাড়াই প্রস্থান করে

প্যাটার্নের পরে কেবল কমান্ডগুলি Nএবং গোষ্ঠীগুলিকে গ্রুপবদ্ধ করে এটি একক-লাইন ইনপুট (এবং প্রকৃতপক্ষে আরও স্পষ্টভাবে স্পষ্ট হওয়া) সহ কাজ করার জন্য সহজেই ঠিক করা যেতে পারে b:

sed ':a;$!{N;ba}; [commands...]'

এটি নিম্নলিখিত হিসাবে কাজ করে:

  1. :a 'একটি' নামে একটি লেবেল তৈরি করুন
  2. $! যদি না শেষ লাইন, তারপর
  3. Nপরের লাইনটি প্যাটার্ন স্পেসে যুক্ত করুন (বা পরবর্তী লাইন না থাকলে ছেড়ে দিন) এবং baশাখা (যান) লেবেল 'এ'

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

sed 'H;1h;$!d;x; [commands...]'

আমি এটি এখানে পোস্ট করেছি কারণ আমি অন্য কোথাও তথ্যটি খুঁজে পাইনি এবং আমি এটি সরবরাহ করতে চেয়েছিলাম যাতে অন্যরা যাতে ব্যাপকভাবে সমস্যা এড়াতে পারে :a;N;$!ba;
ডিকটিয়ার

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