একটি রেজেক্স দ্বারা কোনও ফাইলের একাধিক লাইন কীভাবে পাবেন?


10

একটি রেজেক্স দ্বারা কোনও ফাইলের একাধিক লাইন কীভাবে পাবেন?

আমি প্রায়শই একটি রেজেক্স দ্বারা একাধিক লাইন / একাধিক লাইন সংশোধন করতে চাই। উদাহরণস্বরূপ:

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

এক্সএমএল উদাহরণ:

<tag1>
 <tag2>bar</tag2>
</tag1>
<tag1>
 <tag2>foo</tag2>
</tag1>

এটি থেকে আমি <tag1>এটি পড়তে চাই যদি এটির fooমধ্যে এটি কোথাও থাকে ।

মত একটি Regex (<tag1>.*?foo.*?</tag1>)মত ডান অংশ কিন্তু টুলস দিতে হবে grepএবং sedশুধুমাত্র একক লাইনের আমার জন্য হবে। কিভাবে আমি পেতে পারি

<tag1>
 <tag2>foo</tag2>
</tag1>

এই উদাহরণে?



@ আইভিলসপ সত্য, তবে আমার প্রশ্নটি বিশেষত এক্সএমএল / এসজিএমএল ফাইলগুলি সম্পর্কে নয়, কেবল কোনও পাঠ্য ফাইল সম্পর্কে।
ডেন

উত্তর:


7

আপনি গনুহ, grep ইনস্টল করা থাকে আপনি একাধিক লাইন কথা প্রসঙ্গে দ্বারা অনুসন্ধান করতে পারে -P(Perl-Regex) পতাকা ও সক্রিয় করার PCRE_DOTALLসঙ্গে(?s)

grep -oP '(?s)<tag1>(?:(?!tag1).)*?foo(?:(?!tag1).)*?</tag1>' file.txt
<tag1>
<tag2>foo</tag2>
</tag1>

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

grep -ozP '(?s)<tag1>(?:(?!tag1).)*?foo(?:(?!tag1).)*?</tag1>' file.txt

ওপির উদাহরণ ফাইলটিতে চালিত হওয়ার পরে এটি আমার সিস্টেমে কোনও আউটপুট দেয় না।
টেরডন

আমার জন্য কাজ কর. +1 টি। জন্য ধন্যবাদ (?s)ডগা
নাথন ওয়ালেস

@ ইটারডন, আপনি জিএনইউ গ্রেপের কোন সংস্করণটি চালাচ্ছেন?
iruvar

@ 1_CR দেবিয়ানে (GNU grep) 2.14। আমি ওপিএস উদাহরণটি অনুলিপি করে রেখেছি (কেবলমাত্র চূড়ান্ত নিউলাইন যোগ করে) এবং grepএটিতে আপনার চালিয়েছি কিন্তু কোনও ফল পাইনি।
টেরডন

1
@ এসএলএম, আমি পিসি 6.6 তে আছি, জিএনইউ গ্রেপ 2.5.1 আরএইচইএল-তে। আপনার প্ল্যাটফর্মগুলির grep -ozPপরিবর্তে চেষ্টা করার বিষয়ে কি আপত্তি আছে grep -oP?
iruvar

3
#begin command block
#append all lines between two addresses to hold space 
    sed -n -f - <<\SCRIPT file.xml
        \|<tag1>|,\|</tag1>|{ H 
#at last line of search block exchange hold and pattern space 
            \|</tag1>|{ x
#if not conditional ;  clear buffer ; branch to script end
                \|<tag2>[^<]*foo[^\n]*</tag2>|!{s/.*//;h;b}
#do work ; print result; clear buffer ; close blocks
    s?*?*?;p;s/.*//;h;b}}
SCRIPT

যদি আপনি উপরের কাজটি করে থাকেন, সেখানে প্রদর্শিত শেষ পরিচ্ছন্নতার লাইনের আগে আপনি যে ডেটা দেখিয়েছেন সেগুলি দেওয়াতে, আপনার sedদেখায় এমন একটি প্যাটার্ন স্পেস দিয়ে কাজ করা উচিত :

 ^\n<tag1>\n<tag2>foo</tag2>\n</tag1>$

যখনই আপনি luk দিয়ে পছন্দ করেন আপনি আপনার প্যাটার্নের স্থানটি মুদ্রণ করতে পারেন । তারপরে আপনি \nঅক্ষরগুলিতে সম্বোধন করতে পারেন ।

sed l <file

আপনাকে প্রতিটি লাইনটি sedযে পর্যায়ে lডাকা হয় তার প্রক্রিয়ায় দেখায় ।

সুতরাং আমি এটি পরীক্ষা করেছি এবং প্রথম লাইনে এটির \backslashপরে আরও একটি প্রয়োজন ,commaছিল, তবে অন্যথায় যেমন হয় তেমন কাজ করে। এখানে আমি এটিকে যুক্ত করেছি _sed_functionযাতে আমি পুরো উত্তর জুড়ে সহজেই এটি প্রদর্শনের উদ্দেশ্যে কল করতে পারি: (মন্তব্যগুলির সাথে অন্তর্ভুক্ত রয়েছে তবে ব্রেভিটির জন্য এখানে সরানো হয়েছে)

_sed_function() { sed -n -f /dev/fd/3 
} 3<<\SCRIPT <<\FILE 
    \|<tag1>|,\|</tag1>|{ H
        \|</tag1>|{ x
            \|<tag2>[^<]*foo[^\n]*</tag2>|!{s/.*//;h;b}
    s?*?*?;p;s/.*//;h;b}}
#END
SCRIPT
<tag1>
 <tag2>bar</tag2>
</tag1>
<tag1>
 <tag2>foo</tag2>
</tag1>
FILE


_sed_function
#OUTPUT#
<tag1>
 <tag2>foo</tag2>
</tag1>

এখন আমরা সুইচ করব pএকটি জন্য lতাই আমরা তা দেখতে পারেন আমরা যেমন আমরা আমাদের স্ক্রিপ্ট বিকাশ এবং অ অপ ডেমো অপসারণ কাজ করছি s?আমাদের শেষ লাইন, যাতে sed 3<<\SCRIPTমত শুধু দেখায়:

l;s/.*//;h;b}}

তারপরে আমি এটিকে আবার চালাব:

_sed_function
#OUTPUT#
\n<tag1>\n <tag2>foo</tag2>\n</tag1>$

ঠিক আছে! সুতরাং আমি ঠিক ছিলাম - এটি একটি ভাল অনুভূতি। এখন, আসুন আমরা আমাদের lলাইনটি ঘুরে দেখি যে এটিগুলি যে রেখাগুলি টানছে তবে মুছে ফেলা হয়েছে তা দেখতে। আমরা আমাদের বর্তমানটি সরিয়ে দেব lএবং !{block}এটিতে এটির মতো যুক্ত করব:

!{l;s/.*//;h;b}

_sed_function
#OUTPUT#
\n<tag1>\n <tag2>bar</tag2>\n</tag1>$

আমরা এটি মুছার ঠিক আগে এটি দেখতে দেখতে এটির মতোই।

একটি শেষ জিনিস যা আমি আপনাকে দেখাতে চাই তা হ'ল Hপুরানো স্থানটি এটি তৈরি করার সাথে সাথে। কয়েকটি মূল ধারণা রয়েছে যা আমি আশাবাদী আমি প্রদর্শন করতে পারি। সুতরাং আমি lআবার শেষ ook অপসারণ এবং শেষে Hপুরানো স্থান মধ্যে একটি উঁকি যোগ করার জন্য প্রথম লাইন পরিবর্তন :

{ H ; x ; l ; x

_sed_function
#OUTPUT#
\n<tag1>$
\n<tag1>\n <tag2>bar</tag2>$
\n<tag1>\n <tag2>bar</tag2>\n</tag1>$
\n<tag1>$
\n<tag1>\n <tag2>foo</tag2>$
\n<tag1>\n <tag2>foo</tag2>\n</tag1>$

Hপুরানো স্থান লাইনের চক্র থেকে বেঁচে থাকে - তাই নাম। সুতরাং লোকেরা প্রায়শই কী ট্রিপ করে নেয় - ঠিক আছে, আমি প্রায়শই কী ট্রিপ করি - তা হ'ল এটি ব্যবহার করার পরে এটি মুছতে হবে। xএক্ষেত্রে আমি কেবল একবার ই পরিবর্তন করি , সুতরাং হোল্ড স্পেসটি প্যাটার্ন স্পেস এবং বিপরীত হয়ে যায় এবং এই পরিবর্তনটি লাইনের চক্রগুলিতেও বেঁচে থাকে।

প্রভাবটি হ'ল আমার হোল্ড স্পেসটি মুছতে হবে যা আমার প্যাটার্ন স্পেস হিসাবে ব্যবহৃত হত। আমি প্রথমে বর্তমান প্যাটার্নের স্পেসটি সাফ করে এটি করি:

s/.*//

যা কেবল প্রতিটি চরিত্রকে নির্বাচন করে এবং এটিকে সরিয়ে দেয়। আমি ব্যবহার করতে পারি না dকারণ এটি আমার বর্তমান লাইন চক্রটি শেষ করবে এবং পরবর্তী কমান্ডটি সম্পূর্ণ হবে না, যা আমার স্ক্রিপ্টটিকে প্রায় ট্র্যাশ করবে।

h

এটি এর অনুরূপভাবে কাজ করে Hতবে এটি স্থান ধরে রাখার জায়গাটিকে ওভাররাইট করে, সুতরাং আমি কার্যকরভাবে এটি মুছে ফেলতে আমার ফাঁকা প্যাটার্নের স্থানটি আমার হোল্ড স্পেসের উপরের অংশে অনুলিপি করেছি। এখন আমি ঠিক করতে পারি:

b

বাইরে।

এবং এইভাবেই আমি sedস্ক্রিপ্ট লিখি ।


ধন্যবাদ @ এসএমএল! তুমি কি খুব ভাল ছেলে, তুমি জানো?
মাইকজার্ভ

ধন্যবাদ, চমৎকার, 3k খুব দ্রুত চড়াই, পরের আপ 5k 8-)
SLM

আমি জানি, @ এসএমএল। আমি এখানে কম বেশি শিখতে দেখছি - সম্ভবত ive এর উপযোগিতা আরও বাড়িয়ে দিয়েছে। আমি এটা সম্পর্কে চিন্তা করতে হবে। Ive সবেমাত্র সাইটে কয়েক সপ্তাহ আগে আসা।
মাইকজার্ভ

কমপক্ষে 10 কে যেতে হবে। আনলক করার মূল্যবান সমস্ত কিছু সেই স্তরে। দূরে রেখে দিন, 5 কে এখন মোটামুটি দ্রুত আসবে।
slm

1
আচ্ছা, @ এসএলএম - যাইহোক আপনি এক বিরল জাতের। যদিও আমি একাধিক উত্তর সম্পর্কে একমত না। কিছু Qs বন্ধ হয়ে গেলে কেন এটি আমাকে বাগ দেয় ts তবে বাস্তবে খুব কমই ঘটে। ধন্যবাদ আবার, এসএমএল।
মাইকজার্ভ

2

@ জামেস্পফিনের উত্তরটি পুরোপুরি ভালভাবে কাজ করবে যদি আপনার ফাইলটি উদাহরণের মতো সহজ হয়। আপনার যদি আরও জটিল পরিস্থিতি থাকে যেখানে <tag1>2 টি লাইনের বেশি বিস্তৃত হতে পারে তবে আপনার আরও কিছু জটিল কৌশল প্রয়োজন need উদাহরণ স্বরূপ:

$ cat foo.xml
<tag1>
 <tag2>bar</tag2>
 <tag3>baz</tag3>
</tag1>
<tag1>

 <tag2>foo</tag2>
</tag1>

<tag1>
 <tag2>bar</tag2>

 <tag2>foo</tag2>
 <tag3>baz</tag3>
</tag1>
$ perl -ne 'if(/<tag1>/){$a=1;} 
            if($a==1){push @l,$_}
            if(/<\/tag1>/){
              if(grep {/foo/} @l){print "@l";}
               $a=0; @l=()
            }' foo.xml
<tag1>

  <tag2>foo</tag2>
 </tag1>
<tag1>
  <tag2>bar</tag2>

  <tag2>foo</tag2>
  <tag3>baz</tag3>
 </tag1>

পার্ল স্ক্রিপ্ট আপনার ইনপুট ফাইলের প্রতিটি লাইন প্রক্রিয়া করবে এবং

  • if(/<tag1>/){$a=1;}: যদি একটি খোলার ট্যাগ ( ) পাওয়া যায় তবে চলকটি $aসেট করা 1থাকে <tag1>

  • if($a==1){push @l,$_}: প্রতিটি লাইনের জন্য, যদি $aহয় 1তবে অ্যারেতে এই লাইনটি যুক্ত করুন @l

  • if(/<\/tag1>/) : যদি বর্তমান লাইনটি সমাপনী ট্যাগের সাথে মেলে:

    • if(grep {/foo/} @l){print "@l"}যদি লাইনের কোনো অ্যারের মধ্যে সংরক্ষিত @l(এই মধ্যবর্তী লাইন আছে <tag1>এবং </tag1>স্ট্রিং মিলছে) foo, বিষয়বস্তু প্রিন্ট @l
    • $a=0; @l=(): তালিকাটি খালি করুন ( @l=()) এবং $a0 এ সেট করুন ।

একাধিক <tag1> "foo" রয়েছে এমন ক্ষেত্রে ব্যতীত এটি ভাল কাজ করে। সেক্ষেত্রে এটি প্রথম <tag1> এর শুরু থেকে শেষের শেষ </ tag1> পর্যন্ত প্রতিটি জিনিস মুদ্রণ করে ...
ডেন

@den আমি আমার উত্তরে প্রদর্শিত উদাহরণ দিয়ে এটি পরীক্ষা করেছি যার <tag1>সাথে 3 টি রয়েছে fooএবং এটি দুর্দান্ত কাজ করে। এটি কখন আপনার জন্য ব্যর্থ হয়?
টেরডন


1

এখানে একটি sedবিকল্প রয়েছে:

sed -n '/<tag1/{:x N;/<\/tag1/!b x};/foo/p' your_file

ব্যাখ্যা

  • -n মানে নির্দেশ না দিলে লাইনগুলি মুদ্রণ করবেন না।
  • /<tag1/ প্রথম খোলার ট্যাগের সাথে মেলে
  • :x এই বিন্দুতে পরে জাম্পিং সক্ষম করতে একটি লেবেল
  • N প্যাটার্ন স্পেসে পরবর্তী লাইন যুক্ত করে (সক্রিয় বাফার)।
  • /<\/tag1/!b xএর অর্থ যদি বর্তমান প্যাটার্ন স্পেসে কোনও ক্লোজিং ট্যাগ না থাকে তবে xআগে তৈরি লেবেলে শাখা থাকে । আমরা আমাদের ক্লোজিং ট্যাগ না পাওয়া পর্যন্ত আমরা এভাবে প্যাটার্ন স্পেসে লাইন যুক্ত করতে থাকি।
  • /foo/pমানে যদি বর্তমান প্যাটার্ন স্পেসের সাথে মেলে তবে fooএটি মুদ্রিত করা উচিত।

1

আপনি জিএনইউ অ্যাডকের মাধ্যমে এটি করতে পেরেছিলেন বলে আমি মনে করি, শেষ ট্যাগটিকে একটি রেকর্ড বিভাজক হিসাবে চিকিত্সা করে যেমন একটি পরিচিত শেষ ট্যাগের জন্য </tag1>:

gawk -vRS="\n</tag1>\n" '/foo/ {printf "%s%s", $0, RT}'

বা আরও সাধারণভাবে (শেষ ট্যাগের জন্য একটি রেজেক্স সহ)

gawk -vRS="\n</[^>]*>\n" '/foo/ {printf "%s%s", $0, RT}'

@ টেরডনে এটি পরীক্ষা করা foo.xml:

$ gawk -vRS="\n</[^>]*>\n" '/foo/ {printf "%s%s", $0, RT}' foo.xml
<tag1>

 <tag2>foo</tag2>
</tag1>

<tag1>
 <tag2>bar</tag2>

 <tag2>foo</tag2>
 <tag3>baz</tag3>
</tag1>

0

যদি আপনার ফাইলটি উপরে বর্ণিত ঠিক ঠিক কাঠামোগত হয় তবে আপনি গ্রেপের জন্য -A (এর পরে লাইনগুলি) এবং-বি (আগের লাইন) পতাকা ব্যবহার করতে পারেন ... উদাহরণস্বরূপ:

$ cat yourFile.txt 
<tag1>
 <tag2>bar</tag2>
</tag1>
<tag1>
 <tag2>foo</tag2>
</tag1>
$ grep -A1 -B1 bar yourFile.txt 
<tag1>
 <tag2>bar</tag2>
</tag1>
$ grep -A1 -B1 foo yourFile.txt 
<tag1>
 <tag2>foo</tag2>
</tag1>

যদি আপনার সংস্করণটিকে grepসমর্থন করে তবে আপনি আরও সহজ -C(প্রসঙ্গের জন্য) বিকল্পটি ব্যবহার করতে পারেন যা পার্শ্ববর্তী এন লাইনগুলি প্রিন্ট করে:

$ grep -C 1 bar yourFile.txt 
<tag1>
 <tag2>bar</tag2>
</tag1>

না ধন্যবাদ. এটি কেবলমাত্র একটি উদাহরণ এবং আসল স্টাফগুলি বেশ অনাকাঙ্ক্ষিত মনে হচ্ছে ;-)
ডেন

1
এটি এতে ফু-র সাথে কোনও ট্যাগ খুঁজে পাচ্ছে না, এটি কেবল ফু-সন্ধান করছে এবং প্রসঙ্গের লাইনগুলি প্রদর্শন করছে
নাথান ওয়ালেস

@ নাথানওয়ালেস হ্যাঁ, ওপি যা চেয়েছিল ঠিক তাই, প্রশ্নের উত্তর দেওয়া ক্ষেত্রে এই উত্তরটি পুরোপুরি ভালভাবে কাজ করে।
টেরডন

@terdon যে প্রশ্নটি জিজ্ঞাসা করে তা মোটেই নয়। উক্তি: "আমি <tag1> পড়তে চাই যদি এতে এর মধ্যে কোথাও ফু থাকে" " এই সমাধানটি "foo" যেখানে প্রদর্শিত হবে তা বিবেচনা না করেই "আমি 'foo' এবং প্রসঙ্গে 1 লাইন পড়তে চাই" " আপনার যুক্তি অনুসরণ করে, এই প্রশ্নের একটি সমান বৈধ উত্তর হবে tail -3 input_file.xml। হ্যাঁ এটি এই নির্দিষ্ট উদাহরণের জন্য কাজ করে তবে এটি প্রশ্নের কোনও সহায়ক উত্তর নয়।
নাথান ওয়ালেস

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