दो शब्दों के बीच पाठ निकालने के लिए sed / grep का उपयोग कैसे करें?


134

मैं एक स्ट्रिंग का उत्पादन करने की कोशिश कर रहा हूं जिसमें एक स्ट्रिंग के दो शब्दों के बीच सब कुछ शामिल है:

इनपुट:

"Here is a String"

उत्पादन:

"is a"

का उपयोग करते हुए:

sed -n '/Here/,/String/p'

समापन बिंदु शामिल हैं, लेकिन मैं उन्हें शामिल नहीं करना चाहता।


8
यदि इनपुट है तो परिणाम क्या होना चाहिए Here is a Here String? या I Hereby Dub Thee Sir Stringy?
घोटी

5
FYI करें। आपकी कमांड का अर्थ है उस लाइन के बीच सब कुछ प्रिंट करना, जिसमें यहां शब्द है और जिस लाइन में स्ट्रिंग शब्द है - वह नहीं जो आप चाहते हैं।
हाई वू

अन्य सामान्य sedFAQ है "मैं विशेष लाइनों के बीच पाठ कैसे निकाल सकता हूं"; यह stackoverflow.com/questions/16643288/…
ट्रिपल जूल

जवाबों:


109
sed -e 's/Here\(.*\)String/\1/'

2
धन्यवाद! क्या होगा अगर मैं "यहां" एक है एक स्ट्रिंग है "और" स्ट्रिंग "के बीच सब कुछ ढूंढना चाहता था?" (sed -e's s / one is ((। *) स्ट्रिंग / \ 1 / '?
user1190650

5
@ user1190650 यदि आप "यहाँ एक" के रूप में अच्छी तरह से देखना चाहते हैं तो यह काम करेगा। आप इसे बाहर का परीक्षण कर सकते हैं: echo "Here is a one is a String" | sed -e 's/one is\(.*\)String/\1/'। तुम सिर्फ बीच हिस्सा है और "स्ट्रिंग" "एक है" चाहते हैं, तो आप रेगुलर एक्सप्रेशन से पूरी लाइन से मेल खाते हैं बनाने की जरूरत है: sed -e 's/.*one is\(.*\)String.*/\1/'। Sed में, s/pattern/replacement/"प्रत्येक पंक्ति पर 'पैटर्न के लिए" स्थानापन्न' प्रतिस्थापन कहें। यह केवल "पैटर्न" से मेल खाने वाली किसी भी चीज़ को बदल देगा, इसलिए यदि आप चाहते हैं कि यह पूरी लाइन को बदल दे, तो आपको "पैटर्न" को पूरी लाइन से मिलाने की जरूरत है।
ब्रायन कैंपबेल

9
यह तब टूटता है जब इनपुट होता हैHere is a String Here is a String
Jay D

1
किसी मामले के समाधान को देखने के लिए बहुत अच्छा होगा: "यहाँ एक ब्ला ब्ला ब्ला स्ट्रिंग है यहां 1 ब्ला ब्ला ब्लिंग है यहां 2 ब्लश ब्लश स्ट्रिंग है" आउटपुट को यहां और स्ट्रिंग के बीच केवल पहला विकल्प चुनना चाहिए
जे डी

1
@JayD sed गैर-लालची मिलान का समर्थन नहीं करता है, कुछ अनुशंसित विकल्पों के लिए इस प्रश्न को देखें ।
ब्रायन कैंपबेल

180

GNU grep सकारात्मक और नकारात्मक लुक-फॉरवर्ड और लुक-बैक का भी समर्थन कर सकता है: आपके मामले के लिए, कमांड होगी:

echo "Here is a string" | grep -o -P '(?<=Here).*(?=string)'

अगर वहाँ कई घटनाएं हैं Hereऔर string, आप चुन सकते हैं कि आप पहले Hereऔर आखिरी में stringसे मैच करना चाहते हैं या व्यक्तिगत रूप से उनका मिलान करना चाहते हैं। रेगेक्स के संदर्भ में, इसे लालची मैच (पहला मामला) या गैर-लालची मैच (दूसरा मामला) कहा जाता है

$ echo 'Here is a string, and Here is another string.' | grep -oP '(?<=Here).*(?=string)' # Greedy match
 is a string, and Here is another 
$ echo 'Here is a string, and Here is another string.' | grep -oP '(?<=Here).*?(?=string)' # Non-greedy match (Notice the '?' after '*' in .*)
 is a 
 is another 

31
ध्यान दें कि GNU grep का -Pविकल्प grep* BSD, या किसी भी SVR4 (Solaris इत्यादि) के साथ आने वालों में शामिल नहीं है । FreeBSD में, आप उस devel/pcreपोर्ट को स्थापित कर सकते हैं जिसमें शामिल हैं pcregrep, जो PCRE (और लुक-फॉरवर्ड / पीछे) का समर्थन करता है। OSX के पुराने संस्करणों में GNU grep का उपयोग किया जाता है, लेकिन OSX Mavericks में, -PFreeBSD के संस्करण से लिया गया है, जिसमें विकल्प शामिल नहीं है।
घोटी

1
नमस्ते, मैं केवल अलग सामग्री कैसे निकालूं?
दुर्गेश सुथार १६'१५ को

4
यह काम नहीं करता है क्योंकि यदि आपकी समाप्ति स्ट्रिंग "स्ट्रिंग" एक से अधिक बार होती है, तो इसे अंतिम घटना मिलेगी , अगली घटना नहीं।
ब्यूटेल बटकस

6
के मामले में Here is a string a string, दोनों " is a " और " is a string a "वैध जवाब (उद्धरण की अनदेखी), प्रश्न आवश्यकताओं के अनुसार कर रहे हैं। यह आप पर निर्भर करता है कि आप इनमें से किसे चाहते हैं और फिर उत्तर तदनुसार अलग हो सकता है। वैसे भी, आपकी आवश्यकता के लिए, यह काम करेगा:echo "Here is a string a string" | grep -o -P '(?<=Here).*?(?=string)'
ऐशसेन

2
@BND, आपको pcregrep की बहु-पंक्ति खोज सुविधा को सक्षम करने की आवश्यकता है । echo $'Here is \na string' | grep -zoP '(?<=Here)(?s).*(?=string)'
ऐशसेन

58

स्वीकृत उत्तर उस पाठ को नहीं हटाता है जो पहले Hereया बाद में हो सकता है String। यह करेगा:

sed -e 's/.*Here\(.*\)String.*/\1/'

मुख्य अंतर .*पहले Hereऔर बाद में तुरंत का जोड़ है String


आपका उत्तर आशाजनक है। एक मुद्दा हालांकि। यदि पहली पंक्ति में एक से अधिक स्ट्रिंग हैं, तो मैं इसे पहली बार देखे गए स्ट्रिंग में कैसे निकाल सकता हूँ? धन्यवाद
मियां Asbat अहमद

@MianAsbatAhmad आप *क्वांटिफायर बनाना चाहते हैं , बीच में Hereऔर String, गैर-लालची (या आलसी)। हालाँकि, इस प्रकार के रीजैक्स का इस्तेमाल सेड ने इस स्टाकेवरफ्लो प्रश्न के अनुसार आलसी क्वांटिफायर ( ?तुरंत बाद .*) का समर्थन नहीं करता है । आमतौर पर एक आलसी क्वांटिफायर को लागू करने के लिए आप हर चीज के खिलाफ मैच करेंगे, केवल उस टोकन को छोड़कर, जिसे आप मैच नहीं करना चाहते थे, लेकिन इस मामले में, इसके पूरे स्ट्रिंग के बजाय सिर्फ एक टोकन नहीं है । String
व्हीलर


दुर्भाग्य से यह काम नहीं करता है अगर स्ट्रिंग में लाइन ब्रेक हो
विट्टालो बेनिकियो

यह माना नहीं जाता है। .लाइन टूटने से मेल नहीं खाता। यदि आप लाइन ब्रेक का मिलान करना चाहते हैं, तो आप .कुछ की जगह ले सकते हैं [\s\s]
व्हीलर

35

आप अकेले बैश में स्ट्रिंग्स स्ट्रिप कर सकते हैं:

$ foo="Here is a String"
$ foo=${foo##*Here }
$ echo "$foo"
is a String
$ foo=${foo%% String*}
$ echo "$foo"
is a
$

और अगर आपके पास एक GNU grep है जिसमें PCRE शामिल है , तो आप शून्य-चौड़ाई के दावे का उपयोग कर सकते हैं:

$ echo "Here is a String" | grep -Po '(?<=(Here )).*(?= String)'
is a

यह तरीका इतना धीमा क्यों है? जब इस विधि का उपयोग करते हुए एक बड़े HTML पृष्ठ को अलग किया जाता है तो यह 10 सेकंड की तरह होता है।
एडम जॉन्स

@ अदमजोन, कौन सी विधि? PCRE एक? PCRE पार्स करने के लिए काफी जटिल है, लेकिन 10 सेकंड चरम लगता है। यदि आप चिंतित हैं, तो मैं आपको उदाहरण कोड सहित एक प्रश्न देने की सलाह देता हूं , और देखें कि विशेषज्ञ क्या कहते हैं।
धोती

मुझे लगता है कि यह मेरे लिए बहुत धीमा था क्योंकि यह एक चर में एक बहुत बड़ी HTML फ़ाइल के स्रोत को पकड़े हुए था। जब मैंने फ़ाइल करने के लिए सामग्री लिखी और फिर फ़ाइल को गति दी तो नाटकीय रूप से वृद्धि हुई।
एडम जॉन्स

22

GNU awk के माध्यम से,

$ echo "Here is a string" | awk -v FS="(Here|string)" '{print $2}'
 is a 

grep -P( perl-regexp ) पैरामीटर का समर्थन करता है \K, जो पहले से मिलान किए गए वर्णों को छोड़ने में मदद करता है। हमारे मामले में, पहले से मिलान स्ट्रिंग था Hereइसलिए इसे अंतिम आउटपुट से हटा दिया गया था ।

$ echo "Here is a string" | grep -oP 'Here\K.*(?=string)'
 is a 
$ echo "Here is a string" | grep -oP 'Here\K(?:(?!string).)*'
 is a 

यदि आप चाहते हैं कि आउटपुट हो is aतो आप नीचे की कोशिश कर सकते हैं,

$ echo "Here is a string" | grep -oP 'Here\s*\K.*(?=\s+string)'
is a
$ echo "Here is a string" | grep -oP 'Here\s*\K(?:(?!\s+string).)*'
is a

इसके लिए काम नहीं करता है: echo "Here is a string dfdsf Here is a string" | awk -v FS="(Here|string)" '{print $2}'यह केवल @Avinash Raj is aहोना चाहिएis a is a
alper

20

यदि आपके पास कई मल्टी-लाइन ऑक्युरेन्स के साथ एक लंबी फ़ाइल है, तो पहले नंबर लाइनों को प्रिंट करना उपयोगी है:

cat -n file | sed -n '/Here/,/String/p'

3
धन्यवाद! यह एकमात्र समाधान है जिसने मेरे मामले में काम किया (कई लाइन टेक्स्ट फ़ाइल, बजाय एक स्ट्रिंग के बिना एक लाइन ब्रेक के साथ)। जाहिर है, इसे बिना लाइन नंबरिंग के, -nविकल्प को catछोड़ दिया जाना चाहिए।
जेफरी लेबोव्स्की

... किस मामले में catपूरी तरह से छोड़ा जा सकता है; sedकिसी फ़ाइल या मानक इनपुट को पढ़ना जानता है।
ट्रिपल

9

यह आपके लिए काम कर सकता है (GNU sed):

sed '/Here/!d;s//&\n/;s/.*\n//;:a;/String/bb;$!{n;ba};:b;s//\n&/;P;D' file 

इस तोहफे दो मार्कर (इस उदाहरण में के बीच पाठ की प्रत्येक प्रतिनिधित्व Hereऔर Stringपाठ के भीतर एक नई पंक्ति और बरकरार रखता है नई-पंक्तियों पर)।


7

उपरोक्त सभी समाधानों में कमियां हैं जहां अंतिम खोज स्ट्रिंग को स्ट्रिंग में कहीं और दोहराया जाता है। मुझे बैश फंक्शन लिखना सबसे अच्छा लगा।

    function str_str {
      local str
      str="${1#*${2}}"
      str="${str%%$3*}"
      echo -n "$str"
    }

    # test it ...
    mystr="this is a string"
    str_str "$mystr" "this " " string"

6

आप दो एस कमांड का उपयोग कर सकते हैं

$ echo "Here is a String" | sed 's/.*Here//; s/String.*//'
 is a 

भी काम करता है

$ echo "Here is a StringHere is a String" | sed 's/.*Here//; s/String.*//'
 is a

$ echo "Here is a StringHere is a StringHere is a StringHere is a String" | sed 's/.*Here//; s/String.*//'
 is a 

6

समझ में sedकमांड , हमें इसे चरण दर चरण बनाना होगा।

यहाँ आपका मूल पाठ है

user@linux:~$ echo "Here is a String"
Here is a String
user@linux:~$ 

आइए ubstition विकल्प के Hereसाथ स्ट्रिंग को हटाने का प्रयास करेंssed

user@linux:~$ echo "Here is a String" | sed 's/Here //'
is a String
user@linux:~$ 

इस बिंदु पर, मेरा मानना है कि आप को दूर करने में सक्षम हो जाएगा Stringके रूप में अच्छी तरह से

user@linux:~$ echo "Here is a String" | sed 's/String//'
Here is a
user@linux:~$ 

लेकिन यह आपका वांछित आउटपुट नहीं है।

दो sed कमांड को संयोजित करने के लिए, -eविकल्प का उपयोग करें

user@linux:~$ echo "Here is a String" | sed -e 's/Here //' -e 's/String//'
is a
user@linux:~$ 

उम्मीद है की यह मदद करेगा


4

आप का उपयोग कर सकते हैं \1( http://www.grymoire.com/Unix/Sed.html#uh-4 को देखें ):

echo "Hello is a String" | sed 's/Hello\(.*\)String/\1/g'

कोष्ठक के अंदर की सामग्री को इस प्रकार संग्रहित किया जाएगा \1


यह बीच में कुछ आउटपुट के बजाय तार निकालता है। Sed कमांड में "हेलो" को "के साथ" हटाने का प्रयास करें और यह "हेलो ए"
जोनाथन

1

संकट। मेरे संग्रहीत पंजे मेल संदेश निम्नानुसार लिपटे हुए हैं, और मैं विषय लाइनें निकालने की कोशिश कर रहा हूं:

Subject: [SLC38A9 lysosomal arginine sensor; mTORC1 pathway] Key molecular
 link in major cell growth pathway: Findings point to new potential
 therapeutic target in pancreatic cancer [mTORC1 Activator SLC38A9 Is
 Required to Efflux Essential Amino Acids from Lysosomes and Use Protein as
 a Nutrient] [Re: Nutrient sensor in key growth-regulating metabolic pathway
 identified [Lysosomal amino acid transporter SLC38A9 signals arginine
 sufficiency to mTORC1]]
Message-ID: <20171019190902.18741771@VictoriasJourney.com>

इस थ्रेड में प्रति A2, दो शब्दों के बीच पाठ निकालने के लिए sed / grep का उपयोग कैसे करें? पहली अभिव्यक्ति, नीचे "काम करता है" जब तक मिलान किए गए पाठ में एक नई पंक्ति नहीं होती है:

grep -o -P '(?<=Subject: ).*(?=molecular)' corpus/01

[SLC38A9 lysosomal arginine sensor; mTORC1 pathway] Key

हालांकि, कई प्रकारों की कोशिश करने के बावजूद ( .+?; /s; ...), मुझे ये काम करने के लिए नहीं मिले:

grep -o -P '(?<=Subject: ).*(?=link)' corpus/01
grep -o -P '(?<=Subject: ).*(?=therapeutic)' corpus/01
etc.

समाधान 1।

विभिन्न लाइनों पर दो तार के बीच प्रति अर्क पाठ

sed -n '/Subject: /{:a;N;/Message-ID:/!ba; s/\n/ /g; s/\s\s*/ /g; s/.*Subject: \|Message-ID:.*//g;p}' corpus/01

जो देता है

[SLC38A9 lysosomal arginine sensor; mTORC1 pathway] Key molecular link in major cell growth pathway: Findings point to new potential therapeutic target in pancreatic cancer [mTORC1 Activator SLC38A9 Is Required to Efflux Essential Amino Acids from Lysosomes and Use Protein as a Nutrient] [Re: Nutrient sensor in key growth-regulating metabolic pathway identified [Lysosomal amino acid transporter SLC38A9 signals arginine sufficiency to mTORC1]]                              

समाधान 2. *

प्रति मैं sed का उपयोग करके एक नई पंक्ति (\ n) को कैसे बदल सकता हूं?

sed ':a;N;$!ba;s/\n/ /g' corpus/01

एक स्थान के साथ नए सिरे से जगह लेगा।

कि कैसे दो शब्दों के बीच पाठ निकालने के लिए sed / grep का उपयोग करने के लिए A2 में के साथ ? , हमें मिला:

sed ':a;N;$!ba;s/\n/ /g' corpus/01 | grep -o -P '(?<=Subject: ).*(?=Message-ID:)'

जो देता है

[SLC38A9 lysosomal arginine sensor; mTORC1 pathway] Key molecular  link in major cell growth pathway: Findings point to new potential  therapeutic target in pancreatic cancer [mTORC1 Activator SLC38A9 Is  Required to Efflux Essential Amino Acids from Lysosomes and Use Protein as  a Nutrient] [Re: Nutrient sensor in key growth-regulating metabolic pathway  identified [Lysosomal amino acid transporter SLC38A9 signals arginine  sufficiency to mTORC1]] 

यह संस्करण डबल रिक्त स्थान निकालता है:

sed ':a;N;$!ba;s/\n/ /g; s/\s\s*/ /g' corpus/01 | grep -o -P '(?<=Subject: ).*(?=Message-ID:)'

दे रही है

[SLC38A9 lysosomal arginine sensor; mTORC1 pathway] Key molecular link in major cell growth pathway: Findings point to new potential therapeutic target in pancreatic cancer [mTORC1 Activator SLC38A9 Is Required to Efflux Essential Amino Acids from Lysosomes and Use Protein as a Nutrient] [Re: Nutrient sensor in key growth-regulating metabolic pathway identified [Lysosomal amino acid transporter SLC38A9 signals arginine sufficiency to mTORC1]]

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.