আমি কীভাবে একাধিক লাইন জুড়ে "গ্রেপ" প্যাটার্নগুলি পারি?


24

মনে হচ্ছে আমি grep/ / এর অপব্যবহার করছি egrep

আমি একাধিক লাইনে স্ট্রিংগুলি অনুসন্ধান করার চেষ্টা করছিলাম এবং আমি যা খুঁজেছি তার সাথে মিল থাকা উচিত তা জানতে গিয়ে কোনও মিল খুঁজে পেলাম না। মূলত আমি ভেবেছিলাম যে আমার রেজেক্সগুলি ভুল ছিল তবে আমি অবশেষে পড়লাম যে এই সরঞ্জামগুলি প্রতি লাইনে কাজ করে (এছাড়াও আমার রেজেক্সগুলি এত তুচ্ছ ছিল এটি ইস্যু হতে পারে না)।

সুতরাং কোন একাধিক লাইনে জুড়ে নিদর্শনগুলি অনুসন্ধান করতে কোন সরঞ্জামটি ব্যবহার করবে?



1
@ সিরোস্যান্টিলি - আমি মনে করি না যে এই প্রশ্ন এবং আপনি যেটির সাথে লিঙ্ক করেছেন এটি নকল। অন্য প্রশ্নটি জিজ্ঞাসা করছে যে আপনি মাল্টি-লাইন প্যাটার্ন ম্যাচটি কীভাবে করবেন (অর্থাত এই সরঞ্জামটি কীভাবে ব্যবহার করতে হবে / আমি কী করতে পারি) এটি যখন এটি জিজ্ঞাসা করছে কিভাবে এটি কীভাবে করা যায় grep। এগুলি দৃly়ভাবে সম্পর্কিত তবে ডুপস নয়, আইএমও।
slm

@ সিম এইসব ক্ষেত্রে সিদ্ধান্ত নেওয়া শক্ত: আমি আপনার বক্তব্যটি দেখতে পাচ্ছি। আমি মনে করি যে এই নির্দিষ্ট কেসটি সদৃশ হিসাবে আরও ভাল কারণ ব্যবহারকারী বলেছিলেন "grep""ক্রাইপ করতে" ক্রিয়াপদটি সুপারিশ করেছিল এবং গৃহীত উত্তর সহ শীর্ষ উত্তরগুলি গ্রেপ ব্যবহার করবেন না।
সিরো সান্তিলি 新疆 改造 中心 法轮功 六四

উত্তর:


24

এখানে sedএক যা আপনাকে grepএকাধিক লাইন জুড়ে-অনুরূপ আচরণ দেবে :

sed -n '/foo/{:start /bar/!{N;b start};/your_regex/p}' your_file

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

  • -n প্রতিটি লাইন মুদ্রণের ডিফল্ট আচরণকে দমন করে
  • /foo/{}এটি মেলানোর নির্দেশ দেয় fooএবং স্কুইগলিজের ভিতরে ম্যাচিং লাইনে যা আসে তা করার জন্য নির্দেশ দেয় । fooপ্যাটার্নের শুরুর অংশটি প্রতিস্থাপন করুন ।
  • :start আমরা আমাদের রেইগেক্সের শেষ না পাওয়া পর্যন্ত লুপিং রাখতে সহায়তা করার জন্য একটি ব্রাঞ্চিং লেবেল।
  • /bar/!{}স্কুইগলিজে থাকা লাইনের সাথে মেলে না এমনগুলি কার্যকর করবে barbarপ্যাটার্নের শেষ অংশটি প্রতিস্থাপন করুন ।
  • Nসক্রিয় বাফারে পরবর্তী লাইনটি সংযোজন করে ( sedএটিকে প্যাটার্ন স্পেস বলে)
  • b startstartআমরা পূর্বের তৈরি লেবেলে নিঃশর্তভাবে শাখা করব যাতে পরের লাইনে যতক্ষণ না প্যাটার্ন স্পেস না থাকে ততক্ষণ জুড়ে দেওয়া যায় bar
  • /your_regex/pযদি এটি মেলে তবে প্যাটার্ন স্পেস মুদ্রণ করে your_regex। আপনি your_regexএকাধিক লাইন জুড়ে মেলতে চান পুরো প্রকাশ দ্বারা প্রতিস্থাপন করা উচিত ।

1
+1 এটিকে টুলিকটে যুক্ত করা হচ্ছে! ধন্যবাদ।
wmorrison365

দ্রষ্টব্য: ম্যাকোজে এটি দেয়sed: 1: "/foo/{:start /bar/!{N;b ...": unexpected EOF (pending }'s)
স্ট্যান জেমস

1
পথ sed: unterminated {ত্রুটি
Nomaed

@ নামযুক্ত এখানে অন্ধকারে শট লাগিয়েছেন, কিন্তু আপনার রেজেক্সে কি কোনও "{" অক্ষর রয়েছে? যদি তা হয় তবে আপনাকে এগুলি থেকে পালাতে হবে।
জোসেফ আর

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

19

আমি সাধারণত একটি সরঞ্জাম ব্যবহার করি pcregrepযা বেশিরভাগ লিনাক্সের স্বাদে yumবা ব্যবহার করে ইনস্টল করা যায় apt

যেমন যেমন

ধরুন আপনার যদি testfileকন্টেন্টযুক্ত একটি ফাইল থাকে

abc blah
blah blah
def blah
blah blah

আপনি নিম্নলিখিত কমান্ড চালাতে পারেন:

$ pcregrep -M  'abc.*(\n|.)*def' testfile

একাধিক লাইন জুড়ে প্যাটার্ন ম্যাচিং করতে।

তাছাড়া, আপনি sedপাশাপাশি এটি করতে পারেন ।

$ sed -e '/abc/,/def/!d' testfile

5

পার্ল ব্যবহার করে এখানে একটি সহজ পদ্ধতির:

perl -e '$f=join("",<>); print $& if $f=~/foo\nbar.*\n/m' file

বা (যেহেতু JosephR নেন sedরুট , আমি নির্লজ্জভাবে তার চুরি করব পরামর্শ )

perl -n000e 'print $& while /^foo.*\nbar.*\n/mg' file

ব্যাখ্যা

$f=join("",<>);: এটি পুরো ফাইলটি পড়ে এবং এর বিষয়বস্তুগুলিকে (নিউলাইনস এবং সমস্ত) ভেরিয়েবলে সংরক্ষণ করে $f। তারপরে আমরা মেলাতে চেষ্টা করি foo\nbar.*\nএবং এটি মেলে তবে এটি মুদ্রণ করি (বিশেষ পরিবর্তনশীলটি $&শেষ ম্যাচটি খুঁজে পায়)। ///mনতুন লাইন জুড়ে রেগুলার এক্সপ্রেশন ম্যাচ করতে প্রয়োজন হয়।

-0ইনপুট রেকর্ড বিভাজক সেট করে। 00'অনুচ্ছেদ মোড' সক্রিয় করার জন্য এটি সেট করা যেখানে পার্ল \n\nরেকর্ড বিভাজক হিসাবে পরপর নতুন লাইনের ( ) ব্যবহার করবে will যে কোনও ক্ষেত্রে পরপর নতুন লাইন নেই, পুরো ফাইলটি একবারে (স্লਪਰড) পড়ে।

সতর্কতা:

বড় ফাইলগুলির জন্য এটি করবেন না , এটি পুরো ফাইলটিকে মেমরিতে লোড করবে এবং এটি কোনও সমস্যা হতে পারে।


2

এটি করার একটি উপায় পার্লের সাথে। যেমন এখানে একটি ফাইলের বিষয়বস্তু এখানে দেওয়া হয়েছে foo:

foo line 1
bar line 2
foo
foo
foo line 5
foo
bar line 6

এখন, এখানে কিছু পার্ল রয়েছে যা ফু দিয়ে শুরু হওয়া যে কোনও লাইনের সাথে মিলবে এবং তারপরে বারের সাথে শুরু হওয়া কোনও লাইন থাকবে:

cat foo | perl -e 'while(<>){$all .= $_}
  while($all =~ /^(foo[^\n]*\nbar[^\n]*\n)/m) {
  print $1; $all =~ s/^(foo[^\n]*\nbar[^\n]*\n)//m;
}'

পার্ল, ভেঙে গেছে:

  • while(<>){$all .= $_} এটি ভেরিয়েবলটিতে সম্পূর্ণ স্ট্যান্ডার্ড ইনপুট লোড করে $all
  • while($all =~চলকটির allনিয়মিত প্রকাশ থাকে ...
  • /^(foo[^\n]*\nbar[^\n]*\n)/mরেজেক্স: লাইনের শুরুতে ফু, তারপরে যে কোনও সংখ্যক অ-নিউলাইন অক্ষর, তারপরে একটি নতুন লাইন, তারপরে তত্ক্ষণাত "বার" এবং তারপরে বাকী রেখার বারটি রয়েছে। /mরেজেক্সের শেষে "একাধিক লাইনের সাথে মিল" মানে
  • print $1 রেজেেক্সের যে অংশটি প্রথম বন্ধনে ছিল সেগুলি মুদ্রণ করুন (এই ক্ষেত্রে পুরো নিয়মিত অভিব্যক্তি)
  • s/^(foo[^\n]*\nbar[^\n]*\n)//m রেগেক্সের জন্য প্রথম ম্যাচটি মুছুন, তাই আমরা প্রশ্নে থাকা ফাইলটিতে রেজেক্সের একাধিক মামলার সাথে মিল রাখতে পারি

এবং আউটপুট:

foo line 1
bar line 2
foo
bar line 6

3
আপনার পার্লকে আরও বেশি বুদ্ধিমানের সাথে সংক্ষিপ্ত করা যেতে পারে বলে কেবল খালি ফেলে দেওয়া হয়েছে:perl -n0777E 'say $& while /^foo.*\nbar.*\n/mg' foo
জোসেফ আর

2

গ্রেপ বিকল্প শিফ্ট মাল্টিলাইন ম্যাচিং সমর্থন করে (অস্বীকার: আমি লেখক)।

ধরা যাক testfile:

<বই>
  <শিরোনাম> Lorem Ipsum </title>
  <শিরোনাম> গেম ডাউনলোড করুন
  আপনি যদি কিছু করতে চান, তবে আপনি এটি করতে পারবেন না
  শ্রমকারী এবং মজাদার আলগা </ translation>
</ বই>


sift -m '<description>.*?</description>' (বর্ণনামূলক লাইনগুলি দেখান)

ফলাফল:

টেস্টফাইলে: <বিবরণ> আপনার পছন্দসই সংস্করণ
টেস্টফাইলে: একচেটিয়া শৈলীর কাজ, ইমেডমোড টেম্পোরের মতো কাজ করা উচিত
টেস্টফাইলে: শ্রমজীবী ​​এবং ডলোর ম্যাগনা অ্যালিকা </ বিবরণ>


sift -m '<description>(.*?)</description>' --replace 'description="$1"' --no-filename (বর্ণনাটি বের করুন এবং পুনরায় ফর্ম্যাট করুন)

ফলাফল:

বিবরণ = "গেম ডাউনলোড করুন
  আপনি যদি কিছু করতে চান, তবে আপনি এটি করতে পারবেন না
  মজুর এট ডলোর ম্যাগনা আলিকা "

1
খুব সুন্দর সরঞ্জাম। অভিনন্দন! এটি উবুন্টুর মতো বিতরণে অন্তর্ভুক্ত করার চেষ্টা করুন।
Lourenco

2

কেবলমাত্র একটি সাধারণ গ্রেপ যা Perl-regexpপ্যারামিটার সমর্থন করে Pতা এই কাজটি করবে।

$ echo 'abc blah
blah blah
def blah
blah blah' | grep -oPz  '(?s)abc.*?def'
abc blah
blah blah
def

(?s) ডটল মোডিফায়ার বলা হয় যা কেবলমাত্র অক্ষরগুলিকেই নয় তবে লাইনও ভেঙে দেয় আপনার রেগেক্সে ডট তৈরি করে।


আমি যখন এই সমাধানটি চেষ্টা করি আউটপুটটি 'ডিফ' এ শেষ হয় না তবে 'ব্লাহ' ফাইলটির শেষে চলে যায়
বাকলি ২

হতে পারে আপনার গ্রেপ -Pবিকল্পটি সমর্থন করে না
অবিনাশ রাজ

1

আমি গ্রেপ এবং -আর অপশনটি অন্য একটি গ্রেপের সাথে ব্যবহার করে এটি সমাধান করেছি।

grep first_line_word -A 1 testfile | grep second_line_word

-A 1 বিকল্পটি সন্ধান করা লাইনের পরে 1 লাইন মুদ্রণ করে। অবশ্যই এটি আপনার ফাইল এবং শব্দের সংমিশ্রণের উপর নির্ভর করে। তবে আমার জন্য এটি ছিল দ্রুত এবং নির্ভরযোগ্য সমাধান।


ওরফে গ্রেপ = 'গ্রেপ - কালার = অটো-বি 10 -এ20 -i' এর পরে বিড়াল সামফাইলে | গ্রেপ ব্লাহ | গ্রেপ ফু | গ্রেপ বার ... হ্যাঁ -এ এবং -বি খুব সহজ ... আপনার সেরা উত্তর আছে
স্কট স্টেনসল্যান্ড

1

ধরুন আমাদের কাছে টেস্ট.টেক্সট ফাইল রয়েছে সহ:

blabla
blabla
foo
here
is the
text
to keep between the 2 patterns
bar
blabla
blabla

নিম্নলিখিত কোড ব্যবহার করা যেতে পারে:

sed -n '/foo/,/bar/p' test.txt

নিম্নলিখিত আউটপুট জন্য:

foo
here
is the
text
to keep between the 2 patterns
bar

1

আমরা যদি তাদের বাদ দিয়ে 2 প্যাটার্নের মধ্যে পাঠ্য পেতে চাই।

ধরুন আমাদের কাছে ফাইল রয়েছে টেস্ট.টিএসটিএস সহ:

blabla
blabla
foo
here
is the
text
to keep between the 2 patterns
bar
blabla
blabla

নিম্নলিখিত কোড ব্যবহার করা যেতে পারে:

 sed -n '/foo/{
 n
 b gotoloop
 :loop
 N
 :gotoloop
 /bar/!{
 h
 b loop
 }
 /bar/{
 g
 p
 }
 }' test.txt

নিম্নলিখিত আউটপুট জন্য:

here
is the
text
to keep between the 2 patterns

এটি কীভাবে কাজ করে, চলুন ধাপে ধাপে

  1. /foo/{ যখন লাইনে "foo" থাকে তখন ট্রিগার করা হয়
  2. n পরের রেখার সাথে প্যাটার্নের স্থানটি প্রতিস্থাপন করুন, অর্থাত "এখানে" শব্দটি যুক্ত করুন
  3. b gotoloop "গ্যাটলোপ" লেবেলে শাখা
  4. :gotoloop লেবেলটি "গোটোলোপ" সংজ্ঞা দেয়
  5. /bar/!{ যদি প্যাটার্নটিতে "বার" না থাকে
  6. h প্যাটার্ন সহ হোল্ড স্পেসটি প্রতিস্থাপন করুন, সুতরাং "এখানে" হোল্ড স্পেসে সংরক্ষণ করা হবে
  7. b loop "লুপ" লেবেলে শাখা
  8. :loop লেবেল "লুপ" সংজ্ঞায়িত করে
  9. N হোল্ড স্পেসে প্যাটার্নটি সংযোজন করে।
    এখন হোল্ড স্পেসে রয়েছে:
    "এখানে"
    ""
  10. :gotoloop আমরা এখন চতুর্থ ধাপে আছি এবং একটি লাইনে "বার" উপস্থিত না হওয়া পর্যন্ত লুপ
  11. /bar/ লুপটি সমাপ্ত, "বার" সন্ধান করা হয়েছে, এটি প্যাটার্ন স্পেস
  12. g প্যাটার্ন স্পেসটি হোল্ড স্পেসের সাথে প্রতিস্থাপন করা হয়েছে যা "লু" এবং "বার" এর মধ্যে সমস্ত লাইন রয়েছে যা মূল লুপের সময় সংরক্ষণ করেছে
  13. p প্যাটার্ন স্পেসটি স্ট্যান্ডার্ড আউটপুটে কপি করুন

সম্পন্ন !


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