গ্রেপ আউটপুট কেবল মেলে এমন গ্রুপিং নির্দিষ্ট করে?


289

বলুন আমার কাছে একটি ফাইল রয়েছে:

# file: 'test.txt'
foobar bash 1
bash
foobar happy
foobar

আমি কেবল "ফুবার" এর পরে কী শব্দগুলি উপস্থিত হয় তা জানতে চাই, তাই আমি এই রেজেক্সটি ব্যবহার করতে পারি:

"foobar \(\w\+\)"

প্রথম বন্ধনী ইঙ্গিত দেয় যে ফুবরের ঠিক পরে আমার এই শব্দটির প্রতি বিশেষ আগ্রহ রয়েছে। তবে যখন আমি একটি করি grep "foobar \(\w\+\)" test.txt, আমি কেবল "ফুবারের পরে শব্দ" না দিয়ে পুরো রেখাকে মেলে পুরো রেখাগুলি:

foobar bash 1
foobar happy

আমি অনেক বেশি পছন্দ করতে চাই যে কমান্ডের আউটপুটটি এইরকম দেখায়:

bash
happy

গ্র্যাপিংকে কেবল নিয়মিত অভিব্যক্তিতে গ্রুপিং (বা একটি নির্দিষ্ট গ্রুপিং) এর সাথে মেলে এমন আউটপুট আউটপুট দেওয়ার কোনও উপায় আছে কি?


4
যাদের গ্রিপ দরকার নেই তাদের জন্য:perl -lne 'print $1 if /foobar (\w+)/' < test.txt
ভল্ট

উত্তর:


324

জিএনইউ -Pগ্রেপের পার্ল-স্টাইলের রেজিজেসগুলির -oবিকল্প রয়েছে এবং কেবল প্যাটার্নের সাথে কী মেলে তা মুদ্রণের বিকল্প রয়েছে। এগুলি লক-এওয়ার্ড এ্যাসেরেন্সগুলি (পার্লের ম্যানপেজে বর্ধিত প্যাটার্নগুলির অধীনে বর্ণিত) ব্যবহার করে একত্রিত করা যেতে পারে যার উদ্দেশ্যগুলির সাথে মিলে যাওয়ার জন্য দৃ determined়সংকল্পবদ্ধ থেকে গ্রেপ প্যাটার্নটির কিছু অংশ সরিয়ে ফেলতে -o

$ grep -oP 'foobar \K\w+' test.txt
bash
happy
$

এটি \Kহ'ল সংক্ষিপ্ত-রূপ (এবং আরও কার্যকর ফর্ম) (?<=pattern)যা আপনি আউটপুট করতে চান এমন পাঠ্যের আগে শূন্য-প্রস্থের চেহারা-পিছনের দৃ as়তা হিসাবে ব্যবহার করেন। (?=pattern)আপনি যে পাঠ্যটি আউটপুট করতে চান তার পরে শূন্য-প্রস্থের লুক-ফরোয়ার এডিশন হিসাবে ব্যবহার করা যেতে পারে।

উদাহরণস্বরূপ, যদি আপনি মধ্যে শব্দ মেলে চেয়েছিলেন fooএবং bar, আপনি ব্যবহার করতে পারে:

$ grep -oP 'foo \K\w+(?= bar)' test.txt

বা (প্রতিসম জন্য)

$ grep -oP '(?<=foo )\w+(?= bar)' test.txt

3
আপনার রেজেক্সে গ্রুপিংয়ের চেয়ে বেশি থাকলে আপনি কীভাবে তা করবেন? (শিরোনামটি ইঙ্গিত হিসাবে?)
বার্সেল

4
@ বারাসেল: আমি বিশ্বাস করি না আপনি পারবেন। সময়sed(1)
camh

1
@ ক্যামহ আমি ঠিক পরীক্ষা করেছি যে ওপি'র grep -oP 'foobar \K\w+' test.txtসাথে কিছুই আউটপুট দেয় না test.txt। গ্রেপ সংস্করণটি 2.5.1। ভুল হতে পারে ? O_O
SOUser

@ শিচেনলি: আমি বলতে পারি না। আমি সবেমাত্র গ্রেপ এর v2.5.1 তৈরি করেছি (এটি বেশ পুরানো - 2006 থেকে) এবং এটি আমার পক্ষে কাজ করেছিল।
ক্যামহ

@ সৌসার: আমিও একই অভিজ্ঞতা পেয়েছি - ফাইল করার জন্য কিছুই আউটপুট দেয়। আমার পক্ষে এটি কাজ করে যেমন আউটপুট প্রেরণের জন্য ফাইল নামের আগে '>' অন্তর্ভুক্ত করার জন্য আমি সম্পাদনা অনুরোধ জমা দিয়েছি।
rjchicago

39

স্ট্যান্ডার্ড গ্রেপ এটি করতে পারে না তবে GNU গ্রেপের সাম্প্রতিক সংস্করণগুলি পারে । আপনি সেড, অবাক বা পার্লে ফিরে যেতে পারেন। এখানে কয়েকটি উদাহরণ যা আপনার নমুনা ইনপুটটিতে যা চান তা করেন; কোণার ক্ষেত্রে তারা কিছুটা আলাদা আচরণ করে।

foobar word other stuffদ্বারা প্রতিস্থাপন করুন word, একটি প্রতিস্থাপন সম্পন্ন হলে কেবল মুদ্রণ করুন।

sed -n -e 's/^foobar \([[:alnum:]]\+\).*/\1/p'

প্রথম শব্দটি foobarহলে দ্বিতীয় শব্দটি মুদ্রণ করুন।

awk '$1 == "foobar" {print $2}'

foobarএটি প্রথম শব্দ হলে স্ট্রিপ করুন এবং লাইনটি এড়িয়ে যান অন্যথায়; তারপরে প্রথম সাদা স্থান এবং মুদ্রণের পরে সমস্ত কিছু ফালা করুন।

perl -lne 's/^foobar\s+// or next; s/\s.*//; print'

অসাধারণ! আমি ভেবেছিলাম আমি সিডের সাহায্যে এটি করতে সক্ষম হব, তবে আমি এটি আগে ব্যবহার করিনি এবং আশা করি যে আমি আমার পরিচিত ব্যবহার করতে পারব grep। তবে এই কমান্ডগুলির বাক্য গঠনটি এখন খুব পরিচিত মনে হচ্ছে যে আমি ভিএম-স্টাইল অনুসন্ধানের সাথে পরিচিত এবং + রিজেক্সগুলি প্রতিস্থাপন করি। অসংখ্য ধন্যবাদ.
কোরি ক্লিন

1
গিলস সত্য নয়। একটি জিএনইউ গ্রেপ সমাধানের জন্য আমার উত্তর দেখুন।
ক্যাম

1
@ ক্যাম: আহ, আমি জানতাম না জিএনইউ গ্রেপের এখন পুরো পিসিআরই সমর্থন আছে। আমি আমার উত্তর সংশোধন করেছি, ধন্যবাদ।
গিলস

1
এই উত্তরটি এম্বেডড লিনাক্সের জন্য বিশেষত কার্যকর কারণ grepব্যাসিবক্সের পিসিআরই সমর্থন নেই।
ক্রেগ ম্যাককুইন

স্পষ্টতই উপস্থাপিত একই কাজটি সম্পাদনের একাধিক উপায় রয়েছে, তবে, ওপি যদি গ্রিপ ব্যবহারের জন্য জিজ্ঞাসা করে, তবে আপনি কেন অন্যরকম উত্তর দেন? এছাড়াও, আপনার প্রথম অনুচ্ছেদটি ভুল: হ্যাঁ গ্রেপ এটি করতে পারে।
এফসিএম

32
    sed -n "s/^.*foobar\s*\(\S*\).*$/\1/p"

-n     suppress printing
s      substitute
^.*    anything before foobar
foobar initial search match
\s*    any white space character (space)
\(     start capture group
\S*    capture any non-white space character (word)
\)     end capture group
.*$    anything after the capture group
\1     substitute everything with the 1st capture group
p      print it

1
সিড উদাহরণের জন্য +1, গ্রেপের চেয়ে কাজের জন্য আরও ভাল সরঞ্জাম বলে মনে হচ্ছে। একটি মন্তব্য, ^এবং $যেহেতু বহিরাগত .*এটি একটি লোভী মিল match যাইহোক, তাদের অন্তর্ভুক্ত রেজেক্সের উদ্দেশ্য স্পষ্ট করতে সহায়তা করতে পারে।
টনি

18

ঠিক আছে, আপনি যদি জানেন যে ফুবার সর্বদা প্রথম শব্দ বা লাইন হয় তবে আপনি কাটা ব্যবহার করতে পারেন। তাই ভালো:

grep "foobar" test.file | cut -d" " -f2

-oগ্রেপ- এ স্যুইচটি ব্যাপকভাবে প্রয়োগ করা হয়েছে (Gnu গ্রেপ এক্সটেনশনগুলির চেয়েও বেশি), সুতরাং এটি করার grep -o "foobar" test.file | cut -d" " -f2ফলে এই সমাধানটির কার্যকারিতা বৃদ্ধি পাবে, যা লুকবিহিন এডিশনগুলি ব্যবহারের চেয়ে বেশি বহনযোগ্য।
dubiousjim

আমি বিশ্বাস করি যে আপনি প্রয়োজন হবে grep -o "foobar .*"বা grep -o "foobar \w+"
জি-ম্যান

9

যদি পিসিআরই সমর্থিত না হয় তবে আপনি গ্রেপের দুটি অনুরোধের মাধ্যমে একই ফলাফল অর্জন করতে পারেন। উদাহরণস্বরূপ ফুবারের পরে শব্দটি ধরার জন্য এটি করুন :

<test.txt grep -o 'foobar  *[^ ]*' | grep -o '[^ ]*$'

এই পর একটি অবাধ শব্দ প্রসারণ করা সম্ভব FOOBAR (পাঠযোগ্যতা জন্য Eres সঙ্গে) ভালো:

i=1
<test.txt egrep -o 'foobar +([^ ]+ +){'$i'}[^ ]+' | grep -o '[^ ]*$'

আউটপুট:

1

নোট সূচকটি iশূন্য-ভিত্তিক।


6

pcregrepএকটি স্মার্ট -oবিকল্প রয়েছে যা আপনাকে আউটপুট চায় এমন কোন ক্যাপচারিং গ্রুপগুলি চয়ন করতে দেয়। সুতরাং, আপনার উদাহরণ ফাইলটি ব্যবহার করে,

$ pcregrep -o1 "foobar (\w+)" test.txt
bash
happy

4

ব্যবহার grepক্রস প্ল্যাটফর্মের সাথে সামঞ্জস্যপূর্ণ নয়, যেহেতু -P/ --perl-regexpকেবল জিএনইউতেgrep উপলব্ধ , বিএসডিgrep নয় ।

সমাধানটি এখানে ব্যবহার করে ripgrep:

$ rg -o "foobar (\w+)" -r '$1' <test.txt
bash
happy

অনুসারে man rg:

-r/ --replace REPLACEMENT_TEXTপ্রতিটি পাঠানো টেক্সট প্রতিস্থাপন।

ক্যাপচার গ্রুপ সূচকগুলি (যেমন, $5) এবং নামগুলি (যেমন, $foo) প্রতিস্থাপনের স্ট্রিংয়ে সমর্থিত।

সম্পর্কিত: জিএইচ - 462


2

আমি @ jgshakkey এর উত্তরটি খুব সহায়ক বলে খুঁজে পেয়েছি। grepএটির জন্য এটি খুব ভাল সরঞ্জাম নয়, তবে সেড, যদিও এখানে আমাদের একটি উদাহরণ রয়েছে যা প্রাসঙ্গিক লাইন ধরতে গ্রেপ ব্যবহার করে।

সেডের রেজেক্স সিনট্যাক্সটি যদি আপনি এটি ব্যবহার না করেন তবে আইডিসিঙ্ক্র্যাটিক।

এখানে অন্য উদাহরণ রয়েছে: এটি একটি আইডি পূর্ণসংখ্যা পেতে এক্সপুট আউটপুটকে বিশ্লেষণ করে

⎜   ↳ SynPS/2 Synaptics TouchPad                id=19   [slave  pointer  (2)]

এবং আমি 19 চাই

export TouchPadID=$(xinput | grep 'TouchPad' | sed  -n "s/^.*id=\([[:digit:]]\+\).*$/\1/p")

ক্লাস সিনট্যাক্স নোট করুন:

[[:digit:]]

এবং নিম্নলিখিত এড়ানো প্রয়োজন +

আমি একটাই লাইন ম্যাচ ধরেছি।


আমি ঠিক তাই করার চেষ্টা করছিলাম। ধন্যবাদ!
জেমস

অতিরিক্ত ছাড়াই সামান্য সরল সংস্করণ grep, ধরে নিয়ে 'টাচপ্যাড' 'আইডি' এর বাম দিকে রয়েছে:echo "SynPS/2 Synaptics TouchPad id=19 [slave pointer (2)]" | sed -nE "s/.*TouchPad.+id=([0-9]+).*/\1/p"
অমিত নাইডু
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.