केवल sed के साथ कैप्चर किए गए समूहों को आउटपुट कैसे करें?


277

क्या कोई तरीका है जो sedकेवल कब्जा किए गए समूहों को आउटपुट करने के लिए बताए ? उदाहरण के लिए इनपुट दिया गया:

This is a sample 123 text and some 987 numbers

और मॉडल:

/([\d]+)/

क्या मुझे केवल १ ?३ और ९ in आउटपुट वापस संदर्भों के रूप में मिल सकते हैं?


ध्यान दें, समूह कैप्चर को ध्वज के sedसाथ विस्तारित नियमित अभिव्यक्तियों को चालू करने की आवश्यकता होती है -E
पीटर - मोनिका

जवाबों:


333

इसे काम करने की कुंजी यह बताना sedहै कि आप जो उत्पादन नहीं करना चाहते हैं उसे बाहर करने के साथ-साथ यह भी निर्दिष्ट करें कि आप क्या चाहते हैं।

string='This is a sample 123 text and some 987 numbers'
echo "$string" | sed -rn 's/[^[:digit:]]*([[:digit:]]+)[^[:digit:]]+([[:digit:]]+)[^[:digit:]]*/\1 \2/p'

यह कहता है:

  • प्रत्येक पंक्ति को प्रिंट करने में डिफ़ॉल्ट न हों ( -n)
  • शून्य या अधिक गैर-अंकों को बाहर करें
  • एक या अधिक अंक शामिल करें
  • एक या अधिक गैर-अंकों को बाहर करें
  • एक या अधिक अंक शामिल करें
  • शून्य या अधिक गैर-अंकों को बाहर करें
  • प्रतिस्थापन प्रिंट करें ( p)

सामान्य तौर पर, sedआप कोष्ठक और आउटपुट का उपयोग करके समूहों को कैप्चर करते हैं जो आप एक बैक रेफरेंस का उपयोग करके कैप्चर करते हैं:

echo "foobarbaz" | sed 's/^foo\(.*\)baz$/\1/'

"बार" का उत्पादन करेगा। यदि आप विस्तारित रेगेक्स के लिए -r( -Eओएस एक्स के लिए) उपयोग करते हैं, तो आपको कोष्ठक से बचने की आवश्यकता नहीं है:

echo "foobarbaz" | sed -r 's/^foo(.*)baz$/\1/'

इसमें 9 कैप्चर ग्रुप और उनके बैक रेफरेंस हो सकते हैं। समूहों को दिखाई देने वाले क्रम में पीछे संदर्भ दिए गए हैं, लेकिन उनका उपयोग किसी भी क्रम में किया जा सकता है और दोहराया जा सकता है:

echo "foobarbaz" | sed -r 's/^foo(.*)b(.)z$/\2 \1 \2/'

आउटपुट "एक बार"।

यदि आपके पास GNU है grep(यह OS X सहित BSD में भी काम कर सकता है):

echo "$string" | grep -Po '\d+'

या विविधताएँ जैसे:

echo "$string" | grep -Po '(?<=\D )(\d+)'

-Pविकल्प पर्ल कम्पैटिबल रेग्युलर एक्सप्रेशंस सक्षम बनाता है। देखें man 3 pcrepatternया man 3 pcresyntax


24
एक नोट के रूप में, OSX Mountain Lion अब grep में PCRE का समर्थन नहीं करता है।
yincrash

1
साइड-नोट के रूप में, Solarre 9 पर grep -o विकल्प का समर्थन नहीं किया गया है। इसके अलावा, Solaris 9 sed -r विकल्प का समर्थन नहीं करता है। :(
डैनियल कैट्स

7
अपने sysadmin को grew स्थापित करने के लिए कहें। आपको आश्चर्य होगा कि कुछ डोनट्स आपको क्या मिलेगा ...
avgvstvs

3
ध्यान दें कि आपको '\' के साथ '(' और ')' को उपसर्ग करने की आवश्यकता हो सकती है, मुझे नहीं पता कि क्यों।
लुम्ब्रिक

7
@lumbric: यदि आप sedउदाहरण का उल्लेख कर रहे हैं , यदि आप -rविकल्प का उपयोग करते हैं (या -EOS X, IIRC के लिए) तो आपको कोष्ठक से बचने की आवश्यकता नहीं है। अंतर यह है कि बुनियादी नियमित अभिव्यक्तियों और विस्तारित नियमित अभिव्यक्तियों ( -r) के बीच।
अगली सूचना तक रोक दिया गया।

55

सैड में नौ याद किए गए पैटर्न होते हैं, लेकिन आपको नियमित अभिव्यक्ति के कुछ हिस्सों को याद रखने के लिए बची हुई कोष्ठक का उपयोग करने की आवश्यकता होती है।

उदाहरण और अधिक विस्तार के लिए यहां देखें


58
sed -e 's/version=\(.+\)/\1/' input.txtइस अभी भी उत्पादन पूरी input.txt
पाब्लो

@ पाब्लो, अपने पैटर्न में आपको \+इसके बजाय लिखना है +। और मुझे समझ में नहीं आता कि लोग -eसिर्फ एक सेड कमांड के लिए क्यों इस्तेमाल करते हैं।
फ्रेड्रिक गॉस ने

1
उपयोग sed -e -n 's/version=\(.+\)/\1/p' input.txtदेखें: mikeplate.com/2012/05/09/…
awattar

1
मैं sed -Eतथाकथित "आधुनिक" या "विस्तारित" नियमित अभिव्यक्तियों का उपयोग करने का सुझाव दूंगा जो पर्ल / जावा / जावास्क्रिप्ट / गो / जो भी जायके के बहुत करीब दिखते हैं। (तुलना करें grep -Eया egrep।) डिफ़ॉल्ट सिंटैक्स में उन अजीब भागने के नियम होते हैं और उन्हें "अप्रचलित" माना जाता है। दोनों के बीच अंतर के बारे में अधिक जानकारी के लिए, दौड़ें man 7 re_format
एंड्रयूएफ

31

आप grep का उपयोग कर सकते हैं

grep -Eow "[0-9]+" file

4
@ ghostdog74: बिल्कुल आपसे सहमत हूँ। मैं केवल कैप्चर किए गए समूहों को आउटपुट के लिए greo कैसे प्राप्त कर सकता हूं?
पाब्लो

1
@ मिचेलo - इसीलिए विकल्प है - unixhelp.ed.ac.uk/CGI/man-cgi?grep : -o, - केवल-मिलान केवल PATNN से मेल खाने वाली रेखा के एक हिस्से को दिखाता है
बर्ट F

14
@ बर्ट एफ: मैं मिलान वाले हिस्से को समझता हूं, लेकिन यह समूह पर कब्जा नहीं कर रहा है। मैं जो चाहता हूं, वह इस तरह है ([0-9] +)। + ([abc] {2,3}) इसलिए इसमें कोई अन्य समूह नहीं है। मैं backreferences या किसी और तरह से केवल कैप्चरिंग समूहों को आउटपुट करना चाहता हूं।
पाब्लो

हेलो मिशेल। क्या आप grep द्वारा nth कैप्चर किए गए ग्रुप को निकालने में कामयाब रहे?
doc_id

1
@ पाब्लो: grep का एकमात्र आउटपुट है जो मेल खाता है। इसे कई समूहों को देने के लिए, कई अभिव्यक्तियों का उपयोग करें: grep -Eow -e "[0-9]+" -e "[abc]{2,3}"मुझे नहीं पता कि आपको उन दो अभिव्यक्तियों की आवश्यकता कैसे हो सकती है जो पिछले grep से पाइपिंग से अलग एक पंक्ति में हों (जो कि तब भी काम नहीं कर सकते थे जब या तो पैटर्न एक पंक्ति में एक से अधिक बार मेल खाता हो। )।
इडबरी

13

अंकों का रन (एस)

यह उत्तर अंकों के किसी भी समूह के साथ काम करता है। उदाहरण:

$ echo 'Num123that456are7899900contained0018166intext' |
> sed -En 's/[^0-9]*([0-9]{1,})[^0-9]*/\1 /gp'
123 456 7899900 0018166

विस्तारित उत्तर।

वहाँ उत्पादन करने के लिए sed केवल कब्जा समूहों को बताने के लिए कोई रास्ता नहीं है?

हाँ। कैप्चर ग्रुप द्वारा सभी टेक्स्ट को बदलें:

$ echo 'Number 123 inside text' | sed 's/[^0-9]*\([0-9]\{1,\}\)[^0-9]*/\1/'
123

s/[^0-9]*                           # several non-digits
         \([0-9]\{1,\}\)            # followed by one or more digits
                        [^0-9]*     # and followed by more non-digits.
                               /\1/ # gets replaced only by the digits.

या विस्तारित सिंटैक्स के साथ (कम बैकक्वाट और + के उपयोग की अनुमति दें):

$ echo 'Number 123 in text' | sed -E 's/[^0-9]*([0-9]+)[^0-9]*/\1/'
123

नंबर न होने पर मूल पाठ को प्रिंट करने से बचने के लिए:

$ echo 'Number xxx in text' | sed -En 's/[^0-9]*([0-9]+)[^0-9]*/\1/p'
  • (-n) इनपुट को डिफ़ॉल्ट रूप से प्रिंट न करें।
  • (/ p) केवल तभी प्रिंट करें यदि कोई प्रतिस्थापन किया गया था।

और कई नंबरों का मिलान करने के लिए (और उन्हें प्रिंट भी करें):

$ echo 'N 123 in 456 text' | sed -En 's/[^0-9]*([0-9]+)[^0-9]*/\1 /gp'
123 456

अंकों की किसी भी गणना के लिए यह काम करता है:

$ str='Test Num(s) 123 456 7899900 contained as0018166df in text'
$ echo "$str" | sed -En 's/[^0-9]*([0-9]{1,})[^0-9]*/\1 /gp'
123 456 7899900 0018166

जो कि grep कमांड के समान है:

$ str='Test Num(s) 123 456 7899900 contained as0018166df in text'
$ echo "$str" | grep -Po '\d+'
123
456
7899900
0018166

के बारे में d

और मॉडल: /([\d]+)/

Sed '\ d' (शॉर्टकट) सिंटैक्स को नहीं पहचानता है। ऊपर उपयोग की गई एससीआई समतुल्य समकक्ष [0-9]नहीं है। एकमात्र वैकल्पिक उपाय वर्ण वर्ग का उपयोग करना है: '[[अंक:]]] `।

चयनित उत्तर समाधान बनाने के लिए इस तरह के "चरित्र वर्गों" का उपयोग करते हैं:

$ str='This is a sample 123 text and some 987 numbers'
$ echo "$str" | sed -rn 's/[^[:digit:]]*([[:digit:]]+)[^[:digit:]]+([[:digit:]]+)[^[:digit:]]*/\1 \2/p'

वह समाधान केवल (ठीक) अंकों के दो रन के लिए काम करता है।

बेशक, जैसा कि उत्तर शेल के अंदर निष्पादित किया जा रहा है, हम इस तरह के उत्तर को छोटा बनाने के लिए कुछ चरों को परिभाषित कर सकते हैं:

$ str='This is a sample 123 text and some 987 numbers'
$ d=[[:digit:]]     D=[^[:digit:]]
$ echo "$str" | sed -rn "s/$D*($d+)$D+($d+)$D*/\1 \2/p"

लेकिन, जैसा कि पहले ही समझाया जा चुका है, s/…/…/gpकमांड का उपयोग करना बेहतर है:

$ str='This is 75577 a sam33ple 123 text and some 987 numbers'
$ d=[[:digit:]]     D=[^[:digit:]]
$ echo "$str" | sed -rn "s/$D*($d+)$D*/\1 /gp"
75577 33 123 987

यह अंकों के दोहराए गए रनों को कवर करेगा और शॉर्ट (एर) कमांड लिखेगा।


उच्च मतदान स्वीकार किए गए उत्तर को पढ़ने के बाद आश्चर्यचकित, मैंने इसके संकीर्ण दायरे के बारे में लिखने और वास्तव में प्रश्न की भावना को संबोधित करने के लिए नीचे स्क्रॉल किया। मुझे अंदाजा होना चाहिए कि कोई इसे सालों पहले कर चुका होगा। यह बहुत अच्छी तरह से समझाया गया है और सही सही उत्तर है।
अमित नायडू

9

मेरा मानना ​​है कि प्रश्न में दिया गया पैटर्न केवल उदाहरण के माध्यम से था, और लक्ष्य किसी भी पैटर्न से मेल खाना था ।

यदि आपके पास जीएनयू एक्सटेंशन के साथ एक सीड है, जिसमें पैटर्न स्पेस में एक नई लाइन डालने की अनुमति है, तो एक सुझाव है:

> set string = "This is a sample 123 text and some 987 numbers"
>
> set pattern = "[0-9][0-9]*"
> echo $string | sed "s/$pattern/\n&\n/g" | sed -n "/$pattern/p"
123
987
> set pattern = "[a-z][a-z]*"
> echo $string | sed "s/$pattern/\n&\n/g" | sed -n "/$pattern/p"
his
is
a
sample
text
and
some
numbers

ये उदाहरण CYGWIN के साथ tcsh (हाँ, मैं इसके गलत खोल को जानता हूं ) के साथ हैं। (संपादित करें: बैश के लिए, सेट हटाएं, और रिक्त स्थान चारों ओर =)


@ जोसेफ: धन्यवाद, हालांकि, अपने काम के आधार पर मुझे लगता है कि grep अधिक प्राकृतिक है, जैसे कि ghostdog74 ने सुझाव दिया है। बस यह पता लगाने की जरूरत है कि grep आउटपुट केवल कैप्चर समूहों को कैसे बनाया जाए, पूरे मैच को नहीं।
पाब्लो

2
बस एक नोट, लेकिन प्लस चिह्न '+' का अर्थ है 'एक या अधिक' जो पैटर्न में खुद को दोहराने की आवश्यकता को दूर करेगा। तो, "[0-9] [0-9] *" "बन जाएगा" [0-9] + "
रैंडमइन्सानो

4
@RandomInsano: उपयोग करने के लिए +, आपको इसे से बचने या -rविकल्प ( -EOS X के लिए) का उपयोग करने की आवश्यकता होगी । आप भी उपयोग कर सकते हैं\{1,\} (या -rया -Eएस्केपिंग के बिना)।
अगली सूचना तक रोक दिया गया।

9

छोड़ देना और पर्ल का उपयोग करना

चूंकि sedयह कटौती नहीं करता है, चलो बस तौलिया फेंक दें और पर्ल का उपयोग करें, कम से कम यह एलएसबी है जबकि grepजीएनयू एक्सटेंशन नहीं हैं :-)

  • पूरे मिलान वाले भाग को प्रिंट करें, कोई मेल खाने वाले समूह या ज़रूरत के मुताबिक नहीं:

    cat <<EOS | perl -lane 'print m/\d+/g'
    a1 b2
    a34 b56
    EOS

    आउटपुट:

    12
    3456
  • प्रति पंक्ति एकल मिलान, अक्सर संरचित डेटा फ़ील्ड:

    cat <<EOS | perl -lape 's/.*?a(\d+).*/$1/g'
    a1 b2
    a34 b56
    EOS

    आउटपुट:

    1
    34

    तलाश के साथ:

    cat <<EOS | perl -lane 'print m/(?<=a)(\d+)/'
    a1 b2
    a34 b56
    EOS
  • कई क्षेत्र:

    cat <<EOS | perl -lape 's/.*?a(\d+).*?b(\d+).*/$1 $2/g'
    a1 c0 b2 c0
    a34 c0 b56 c0
    EOS

    आउटपुट:

    1 2
    34 56
  • प्रति पंक्ति कई मैच, अक्सर असंरचित डेटा:

    cat <<EOS | perl -lape 's/.*?a(\d+)|.*/$1 /g'
    a1 b2
    a34 b56 a78 b90
    EOS

    आउटपुट:

    1 
    34 78

    तलाश के साथ:

    cat EOS<< | perl -lane 'print m/(?<=a)(\d+)/g'
    a1 b2
    a34 b56 a78 b90
    EOS

    आउटपुट:

    1
    3478

1
आपको प्रश्न के अंत के साथ क्या नहीं मिला: "सेड के साथ"?
मूनचाइल्ड

@ मूनचाइल्ड गोगलर्स परवाह नहीं करते हैं।
सिरो सेंटिल्ली। Iro i i ''

1
मुझे यह उपयोगी लगा। सभी कमांड लाइन regex समस्याओं को sed के साथ हल करने की आवश्यकता नहीं है।
PPPaul

5

प्रयत्न

sed -n -e "/[0-9]/s/^[^0-9]*\([0-9]*\)[^0-9]*\([0-9]*\)[^0-9]*\([0-9]*\)[^0-9]*\([0-9]*\)[^0-9]*\([0-9]*\)[^0-9]*\([0-9]*\)[^0-9]*\([0-9]*\)[^0-9]*\([0-9]*\)[^0-9]*\([0-9]*\).*$/\1 \2 \3 \4 \5 \6 \7 \8 \9/p"

मुझे यह साइबरविन के तहत मिला:

$ (echo "asdf"; \
   echo "1234"; \
   echo "asdf1234adsf1234asdf"; \
   echo "1m2m3m4m5m6m7m8m9m0m1m2m3m4m5m6m7m8m9") | \
  sed -n -e "/[0-9]/s/^[^0-9]*\([0-9]*\)[^0-9]*\([0-9]*\)[^0-9]*\([0-9]*\)[^0-9]*\([0-9]*\)[^0-9]*\([0-9]*\)[^0-9]*\([0-9]*\)[^0-9]*\([0-9]*\)[^0-9]*\([0-9]*\)[^0-9]*\([0-9]*\).*$/\1 \2 \3 \4 \5 \6 \7 \8 \9/p"

1234
1234 1234
1 2 3 4 5 6 7 8 9
$

2

यह वह नहीं है जो ओपी ने (समूहों को कैप्चर करने) के लिए कहा है, लेकिन आप संख्याओं का उपयोग करके निकाल सकते हैं:

S='This is a sample 123 text and some 987 numbers'
echo "$S" | sed 's/ /\n/g' | sed -r '/([0-9]+)/ !d'

निम्नलिखित देता है:

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