দুটি লাইন অভিন্ন কিনা তা পরীক্ষা করতে প্রাক্তন কমান্ডটি ব্যবহার করুন?


9

আমি এই প্রশ্নের দিকে তাকিয়ে ছিলাম এবং তখন ভাবছিলাম যে আমি কীভাবে আমার উত্তরটিsed কার্যকর করতে পারি যা নিখুঁতভাবে পসিক্স exব্যবহার করে ।

কৌশলটি হ'ল sedআমি হোল্ড স্পেসটির সাথে প্যাটার্ন স্পেসের সাথে তুলনা করতে পারি যে তারা ঠিক সমান (যদি G;/^\(.*\)\n\1$/{do something}) হয় তবে আমি এ জাতীয় পরীক্ষা করার কোনও উপায় জানি না ex

আমি জানি যে ভিমে আমি Yপ্রথম লাইনটি আঁকতে পারি এবং তারপরে আমি যা নির্দিষ্ট করে যাচ্ছিলাম তা প্রায় টাইপ :2,$g/<C-r>0/dকরতে পারি — তবে প্রথম লাইনে খুব সরল অক্ষরযুক্ত লেখা ছাড়া কিছু থাকলে এটি প্রকৃতপক্ষে পরিণত হয়, যেহেতু রেখাটি রেজেক্স হিসাবে ফেলে দেওয়া হচ্ছে , তুলনার জন্য কেবল একটি স্ট্রিং নয়। (এবং যদি প্রথম লাইনে একটি ফরোয়ার্ড স্ল্যাশ থাকে তবে বাকী রেখাটি একটি কমান্ড হিসাবে ব্যাখ্যা করা হবে!)

সুতরাং আমি যদি সেই সমস্ত লাইন মুছে ফেলতে চাই myfileতবে প্রথম লাইনের অনুরূপ — তবে প্রথম লাইনটি মুছতে না পারি using আমি কীভাবে এটি ব্যবহার করে করতে পারি ex? এই বিষয়টির জন্য, আমি কীভাবে এটি ব্যবহার করে করতে পারি vi?

কোনও লাইনটি অন্য লাইনের সাথে হুবহু মিলে গেলে মুছার কোনও পসিক্স উপায় আছে?

সম্ভবত এই কল্পিত সিনট্যাক্স এর মতো কিছু:

:2,$g/**lines equal to "0**/d

3
আপনি কমান্ড নির্মান করতে পারে, কিন্তু এটা vimscript একটি সামান্য বিট প্রয়োজন হবে এবং এটি সম্ভবত হবে না একটি POSIX উপায়::execute '2,$g/\V' . escape(getline(1), '\') . '/d'
Saginaw

1
@ সাগিনা, ধন্যবাদ এখনও পর্যন্ত আমার কাছে ঘটে যাওয়া একমাত্র পসিক্স পন্থাটি হ'ল কেবলমাত্র sedএকটি ফিল্টার হিসাবে কেবল অভ্যন্তর থেকে ব্যবহার করা exএবং আমার পুরো sedউত্তরটি পুরো বাফারে চালানো ... যা অবশ্যই কাজ করবে (এবং আসলে এটির বিপরীতে রয়েছে sed -i)।
ওয়াইল্ডকার্ড

আপনি ঠিক বলেছেন এবং আমি আপনার প্রাথমিক পদ্ধতির <C-r>0খুব ভাল সঙ্গে খুঁজে । আমি নিশ্চিত না যে আপনি কেবলমাত্র প্রাক্তন কমান্ড দিয়ে আরও ভাল করতে পারবেন কারণ আপনাকে বিশেষ অক্ষরগুলি রক্ষা করতে হবে। পসিক্স আনুগত্যের সীমাবদ্ধতা ব্যতীত আমি মনে করি আপনি খুব অলৌকিক সুইচটি ব্যবহার করবেন \Vএবং তারপরে আপনি ব্যাকস্ল্যাশটিকে সুরক্ষিত করবেন (কারণ এটি এর সাথে তার বিশেষ অর্থ রাখে \V) escape()যার দ্বিতীয় তর্কটি এমন একটি স্ট্রিং যার মধ্যে আপনি পালাতে চান / সুরক্ষা চান ।
saginaw

যাইহোক, পূর্ববর্তী কমান্ডে আমিও ফরওয়ার্ড স্ল্যাশ রক্ষা করতে ভুলে গিয়েছিলাম, কারণ এটির বৈশ্বিক কমান্ডেরও একটি বিশেষ অর্থ রয়েছে, এটি প্যাটার্ন ডিলিমিটার। সুতরাং সঠিক কমান্ডটি সম্ভবত এর মতো কিছু হবে: :execute '2,$g/\V' . escape(getline(1), '\/') . '/d'বা আপনি অর্ধিকলের মতো প্যাটার্ন ডিলিমিটারের জন্য অন্য একটি অক্ষর ব্যবহার করতে পারেন। এক্ষেত্রে আপনার প্যাটার্নে ফরোয়ার্ড স্ল্যাশ রক্ষা করার প্রয়োজন হবে না। এটি এমন কিছু দেবে::execute '2,$g;\V' . escape(getline(1), '\') . ';d'
সাগিনো

1
আমি sedখুব ভাল সঙ্গে আপনার দ্বিতীয় পদ্ধতির খুঁজে । ভিমের সাথে, আপনি প্রায়শই অন্যান্য প্রোগ্রামগুলিতে কিছু বিশেষ কাজগুলি অর্পণ করেন এবং sedসম্ভবত এটির একটি ভাল উদাহরণ। যাইহোক, sedআপনার পুরো বাফারটি চালাতে হবে না । আপনি যদি এটি কেবল বাফারের একটি অংশে চালাতে চান তবে আপনি একটি পরিসর দিতে পারেন। উদাহরণস্বরূপ, যদি আপনি 50 থেকে 100 এর মধ্যে শুধুমাত্র লাইন ফিল্টার করতে চান, আপনি টাইপ পারে: :50,100!<your sed command>
saginaw

উত্তর:


3

তেজ

ভিমে আপনি নিউলাইন সহ যে কোনও চরিত্রের সাথে মিল রাখতে পারেন \_.। আপনি পুরো লাইন, যেকোন পরিমাণের স্টাফ এবং তারপরে একই লাইনের সাথে মেলে এমন একটি প্যাটার্ন তৈরি করতে এটি ব্যবহার করতে পারেন:

/\(^.*$\)\_.*\n\1$/

এখন আপনি কোনও ফাইলের মধ্যে সমস্ত লাইন মুছতে চান যা প্রথমটি না মিলিয়ে প্রথমটির সাথে মেলে। প্রথমটির সাথে মেলে সর্বশেষ লাইনটি মুছে ফেলার বিকল্পটি হ'ল:

:1 s/\(^.*$\)\_.*\zs\n\1$//

আপনি :globalসমস্ত লাইন মুছে ফেলার জন্য বিকল্পটি যথেষ্ট সময় পুনরাবৃত্তি হয়েছে তা নিশ্চিত করতে ব্যবহার করতে পারেন :

:g/^/ 1s/\(^.*$\)\_.*\zs\n\1$//

পজিক্স প্রাক্তন

আপনার প্রশ্নটির মন্তব্যে @ সাগিনাও ভিমে এটি করার একটি সুপরিচিত উপায় দেখায়, তবে আমরা পসিক্স প্রাক্তনের জন্য উপরের কৌশলটি গ্রহণ করতে পারি।

পসিক্স-সামঞ্জস্যপূর্ণ উপায়ে এটি করতে আপনাকে মাল্টি-লাইন মিলাকে বঞ্চিত করতে হবে, তবে আপনি এখনও ব্যাক-রেফারেন্স ব্যবহার করতে পারেন। এর জন্য কিছু অতিরিক্ত কাজ প্রয়োজন:

:g/^/ t- | s/^/@@@/ | 1t- | s/^/"/ | j! | s/^"\(.*\)@@@\1$/d/ | d x | @x

এখানে ভাঙ্গন:

:g/^/                   for each line

t- |                    copy it above

s/^/@@@/ |              prefix it with something unique (@@@)
                        (do a search in the buffer first to make
                        sure it really is unique)

1t- |                   copy the first line above this one

s/^/"/ |                prefix with "

j! |                    join those two lines (no spaces)

s/^"\(.*\)@@@\1$/d/ |   if the part after the " and before the @@@
                        matches the part after the @@@, replace the line
                        with d

d x |                   delete the line into register x

@x                      execute it

সুতরাং বর্তমান লাইনটি যদি লাইন 1 এর সদৃশ হয় তবে রেজিস্টার এক্স থাকবে d। এটি কার্যকর করা বর্তমান লাইনটি মুছে ফেলবে। যদি এটি সদৃশ না হয় তবে এটিতে কোনও অগ্রাহ্য করা হবে, "যার সাথে মৃত্যুদন্ড কার্যকর করা হবে যখন একটি নো-অপি হবে, যেহেতু " একটি মন্তব্য শুরু হয়। আমি জানি না এটি সম্পাদন করার জন্য এটি সবচেয়ে নিকৃষ্টতম উপায়, এটি কেবল প্রথম মনে আসল!

এটি ঠিক তাই ঘটে যে প্রথম লাইনটি মোছা যায় না কারণ অনুলিপি করার প্রক্রিয়া অস্থায়ীভাবে 1 লাইনটি কী তা পরিবর্তন করে। যদি এটি না হয়ে থাকে তবে আপনি পরিবর্তে :gএকটি 2,$ব্যাপ্তির সাথে উপসর্গ করতে পারেন ।

ভিম এবং প্রাক্তন- vi সংস্করণ 4.0 এ পরীক্ষিত।

সম্পাদনা

এবং একটি সহজ উপায়, যা অনুসন্ধানের প্যাটার্ন ( 'nomagic'সেট সহ) তৈরি করতে বিশেষ অক্ষরগুলি থেকে পালিয়ে যায় , একটি :globalআদেশ তৈরি করে , তারপরে এটি সম্পাদন করে:

:set nomagic
:1t1 | .g/^/ s#\[$^\/]#\\\&#g | s#\.\*#2,$g/^\&$/d# | d x
:@x
:set magic

আপনি যদিও এটি নেস্টেড থাকতে চান, তবে এটি ওয়ান-লাইনার হিসাবে এটি করতে পারবেন না :globalwhich


2

এটি প্রদর্শিত হবে যে এটি করার একমাত্র POSIX উপায় হ'ল বাহ্যিক ফিল্টার ব্যবহার করা sed

উদাহরণস্বরূপ, আপনার ফাইলের 17 তম লাইনটি কেবলমাত্র 5 তম লাইনের সাথে সাদৃশ্যপূর্ণভাবে মুছতে এবং অন্যথায় এটি অপরিবর্তিত রেখে দিতে, আপনি নিম্নলিখিতটি করতে পারেন:

:1,17!sed '5h;17{G;/^\(.*\)\n\1$/d;s/\n.*$//;}'

(আপনি sedএখানে পুরো বাফারে চালাতে পারেন, বা আপনি কেবল 5-17 লাইনে চালাতে পারেন, তবে প্রথম ক্ষেত্রে আপনি অপ্রয়োজনীয় ফিল্টারিং করছেন - কোনও বড় বিষয় নয়) এবং পরবর্তী ক্ষেত্রে আপনাকে এটি ব্যবহার করতে হবে আপনার sedকমান্ডে 5 এবং 17 এর পরিবর্তে 1 এবং 13 নম্বর দিন Conf বিভ্রান্তিমূলক))

যেহেতু sedকেবল একটি একক ফরোয়ার্ড পাস করে, তাই 17 তম লাইনের সমতুল্য হয়ে থাকলে 5 তম লাইনটি বিপরীত করার এবং মুছার কোনও সহজ উপায় নেই। আমি কৌতূহলের বিষয় হিসাবে কিছুক্ষণ চেষ্টা করেছিলাম ... এটা কৌতূহলপূর্ণ


ব্রেকথ্রু - আপনি এটি এর মতো করতে পারেন:

:17t 5
:5,5+!sed '1N;/^\(.*\)\n\1$/d;s/\n.*$//'

এটি আসলে আরও সাধারণ পদ্ধতি। এটি একইভাবে প্রথম আদেশ হিসাবে একই ফলাফল দিতে ব্যবহার করা যেতে পারে (এবং 17 তম লাইনের সাথে এটি 5 তম লাইনের অনুরূপ হলে মুছুন):

:5t 17
:17,17+!sed '1N;/^\(.*\)\n\1$/d;s/\n.*$//'

বিস্তৃত ব্যবহারের জন্য যেমন লাইন 37 এর অনুরূপ ফাইলের সমস্ত লাইন মুছে ফেলা , লাইন 37 অক্ষত রেখে যাওয়ার সময় আপনি নিম্নলিখিতটি করতে পারেন:

:37,$!sed '1{h;n;};G;/^\(.*\)\n\1$/d;s/\n.*$//'
:37t 0
:1,37!sed '1{h;d;};G;/^\(.*\)\n\1$/d;s/\n.*$//'

উপসংহার এখানে যদি দুই লাইন অভিন্ন, সেরা টুল চেক করার জন্য, হয় হয় sed , না ex। কিন্তু DevSolar একটি মন্তব্যে উল্লিখিত , এই ব্যর্থতা নয় viবা ex-তারা হয় পরিকল্পিত ইউনিক্স সরঞ্জামগুলির সাথে কাজ; যে একটি বড় শক্তি।


অনেক বেশি কঠিন: ফাইলের শেষে একটি লাইন সন্নিবেশ করা, কেবলমাত্র যদি লাইনটি ফাইলের কোথাও কোথাও উপস্থিত না থাকে ।
ওয়াইল্ডকার্ড

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