आसपास के पात्रों को छापे बिना 'सेड' से मिलान किए गए एक रेग्क्स को निकालना


24

सभी 'सेड' डॉक्टरों को वहाँ से बाहर:

आप एक पंक्ति में मेल खाते हुए एक नियमित अभिव्यक्ति निकालने के लिए 'सेड' कैसे प्राप्त कर सकते हैं?

दूसरे शब्दों में, मैं चाहता हूं कि सभी गैर-मिलान वाले पात्रों के साथ नियमित अभिव्यक्ति के अनुरूप स्ट्रिंग को छीन लिया गया।

मैंने नीचे की तरह बैक-रेफरेंस फीचर का उपयोग करने की कोशिश की

regular expression to be isolated 
         gets `inserted` 
              here     
               |
               v  
 sed -n 's/.*\( \).*/\1/p 

यह कुछ भावों की तरह काम करता है

 sed -n 's/.*\(CONFIG_[a-zA-Z0-9_]*\).*/\1/p 

जो बड़े करीने से 'CONFIG_ ....' से शुरू होने वाले सभी मैक्रो नामों को निकालता है (कुछ '* .h' फ़ाइल में पाया जाता है) और उन सभी को लाइन से प्रिंट करता है।

          CONFIG_AT91_GPIO
          CONFIG_DRIVER_AT91EMAC
                   .
                   .   
          CONFIG_USB_ATMEL
          CONFIG_USB_OHCI_NEW
                   .
                 e.t.c. 

लेकिन ऊपर के टूटने के लिए कुछ की तरह नीचे

  sed -n 's/.*\([0-9][0-9]*\).*/\1/p 

यह हमेशा की तरह एकल अंक लौटाता है

                 7
                 9
                 .
                 .  
                 6

एक सन्निहित संख्या क्षेत्र जैसे निकालने के बजाय।

              8908078
              89670890  
                 .
                 .  
                 .
               23019   
                 .
               e.t.c.  

पुनश्च: मैं इस पर प्रतिक्रिया के लिए आभारी रहूंगा कि यह 'सेड' में कैसे प्राप्त होता है। मुझे पता है कि यह कैसे करना है 'grep' और 'awk' के साथ मैं यह पता लगाना चाहूंगा कि क्या मेरे - यद्यपि सीमित - 'सेड' की समझ इसमें छेद है और अगर 'sed' में ऐसा करने का कोई तरीका है जो मेरे
पास है बस अनदेखा कर दिया।

जवाबों:


22

जब एक regexp में समूह होते हैं, तो इसके खिलाफ एक स्ट्रिंग से मेल खाने का एक से अधिक तरीका हो सकता है: समूहों के साथ regexps अस्पष्ट हैं। उदाहरण के लिए, regexp ^.*\([0-9][0-9]*\)$और स्ट्रिंग पर विचार करें a12। दो संभावनाएँ हैं:

  • के aखिलाफ .*और 2खिलाफ मैच [0-9]*; 1द्वारा मिलान किया जाता है [0-9]
  • मैच के a1खिलाफ .*और खाली स्ट्रिंग के खिलाफ [0-9]*; 2द्वारा मिलान किया जाता है [0-9]

एसईडी, अन्य सभी रेगेक्सप टूल्स की तरह, सबसे लंबा सबसे लंबा मैच नियम लागू करता है: यह पहली बार एक स्ट्रिंग के खिलाफ पहले वैरिएबल-लंबाई वाले हिस्से से मिलान करने की कोशिश करता है जो कि यथासंभव लंबे समय तक होता है। यदि यह शेष रेगेक्सपी के खिलाफ बाकी स्ट्रिंग से मिलान करने का एक तरीका ढूंढता है, तो ठीक है। अन्यथा, sed पहले चर-लंबाई वाले हिस्से के लिए अगले सबसे लंबे मैच की कोशिश करता है और फिर से कोशिश करता है।

यहां, सबसे लंबे स्ट्रिंग के साथ मैच पहले के a1खिलाफ है .*, इसलिए समूह केवल मैच करता है 2। यदि आप चाहते हैं कि समूह पहले शुरू हो, तो कुछ regexp इंजन आपको .*कम लालची बनाते हैं , लेकिन sed में ऐसी सुविधा नहीं है। तो आपको कुछ अतिरिक्त एंकर के साथ अस्पष्टता को दूर करने की आवश्यकता है । निर्दिष्ट करें कि अग्रणी .*एक अंक के साथ समाप्त नहीं हो सकता है, ताकि समूह का पहला अंक पहला संभव मैच हो।

  • यदि अंकों का समूह लाइन की शुरुआत में नहीं हो सकता है:

    sed -n 's/^.*[^0-9]\([0-9][0-9]*\).*/\1/p'
    
  • यदि अंकों का समूह लाइन की शुरुआत में हो सकता है, और आपका sed \?वैकल्पिक भागों के लिए ऑपरेटर का समर्थन करता है :

    sed -n 's/^\(.*[^0-9]\)\?\([0-9][0-9]*\).*/\1/p'
    
  • यदि अंकों का समूह लाइन की शुरुआत में हो सकता है, तो मानक रेगेक्स निर्माणों से चिपके रहते हैं:

    sed -n -e 's/^.*[^0-9]\([0-9][0-9]*\).*/\1/p' -e t -e 's/^\([0-9][0-9]*\).*/\1/p'
    

वैसे, यह सबसे पुराना सबसे लंबा मैच नियम है जो [0-9]*बाद के बजाय पहले एक के बाद के अंकों से मेल खाता है .*

ध्यान दें कि यदि किसी रेखा पर अंकों के कई अनुक्रम हैं, तो आपका कार्यक्रम हमेशा अंकों के अंतिम अनुक्रम को निकालेगा, प्रारंभिक के लिए सबसे लंबे समय तक मिलान नियम के कारण .*। यदि आप अंकों के पहले अनुक्रम को निकालना चाहते हैं, तो आपको यह निर्दिष्ट करना होगा कि जो पहले आता है वह गैर-अंकों का अनुक्रम है।

sed -n 's/^[^0-9]*\([0-9][0-9]*\).*$/\1/p'

अधिक आम तौर पर, एक regexp के पहले मैच को निकालने के लिए, आपको उस regexp के निषेध की गणना करने की आवश्यकता है। जबकि यह हमेशा सैद्धांतिक रूप से संभव होता है, नकार का आकार तेजी से बढ़ता है उस regexp के आकार के साथ जो आप नकार रहे हैं, इसलिए यह अक्सर अव्यवहारिक होता है।

अपने अन्य उदाहरण पर विचार करें:

sed -n 's/.*\(CONFIG_[a-zA-Z0-9_]*\).*/\1/p'

यह उदाहरण वास्तव में एक ही मुद्दे को प्रदर्शित करता है, लेकिन आप इसे विशिष्ट इनपुट पर नहीं देखते हैं। यदि आप इसे खिलाते हैं hello CONFIG_FOO_CONFIG_BAR, तो ऊपर का कमांड प्रिंट करता है CONFIG_BAR, नहीं CONFIG_FOO_CONFIG_BAR

पहले मैच को sed के साथ प्रिंट करने का एक तरीका है, लेकिन यह थोड़ा मुश्किल है:

sed -n -e 's/\(CONFIG_[a-zA-Z0-9_]*\).*/\n\1/' -e T -e 's/^.*\n//' -e p

(मान लिया जाए कि आपकी सेड रिप्लेसमेंट टेक्स्ट \nमें एक न्यूलाइन का मतलब है s।) यह काम करता है क्योंकि सेड रेक्सएक्सपी के सबसे शुरुआती मैच के लिए दिखता है, और हम उस CONFIG_…बिट को प्रीएर्ड करने की कोशिश नहीं करते हैं । चूंकि लाइन के अंदर कोई नई रेखा नहीं है, इसलिए हम इसे अस्थायी मार्कर के रूप में उपयोग कर सकते हैं। Tआदेश देने के लिए करता है, तो पूर्ववर्ती कहते हैं sआदेश मेल नहीं खाती।

जब आप समझ नहीं सकते कि कैसे कुछ सेड में किया जाए, तो जागने के लिए मुड़ें। निम्न कमांड एक regexp का सबसे लंबा सबसे लंबा मैच प्रिंट करता है:

awk 'match($0, /[0-9]+/) {print substr($0, RSTART, RLENGTH)}'

और अगर आपको यह आसान लग रहा है, तो पर्ल का उपयोग करें।

perl -l -ne '/[0-9]+/ && print $&'       # first match
perl -l -ne '/^.*([0-9]+)/ && print $1'  # last match

22

जबकि नहीं sed , चीजों में से एक को अक्सर इसके लिए अनदेखा किया जाता है grep -o, जो मेरी राय में इस कार्य के लिए बेहतर उपकरण है।

उदाहरण के लिए, यदि आप CONFIG_कर्नेल कॉन्फ़िगरेशन से सभी पैरामीटर प्राप्त करना चाहते हैं, तो आप उपयोग करेंगे:

# grep -Eo 'CONFIG_[A-Z0-9_]+' config
CONFIG_64BIT
CONFIG_X86_64
CONFIG_X86
CONFIG_INSTRUCTION_DECODER
CONFIG_OUTPUT_FORMAT

यदि आप संख्याओं के सन्निहित अनुक्रम प्राप्त करना चाहते हैं:

$ grep -Eo '[0-9]+' foo

7
sed '/\n/P;//!s/[0-9]\{1,\}/\n&\n/;D'

... किसी भी उपद्रव को इस w / बाहर कर देगा, हालांकि आपको nदाएं हाथ के प्रतिस्थापन क्षेत्र में एस के स्थान पर शाब्दिक नए समाचारों की आवश्यकता हो सकती है । और, वैसे, ए.*CONFIG बात केवल तभी काम करेगी जब लाइन पर केवल एक ही मैच हो - यह अन्यथा हमेशा केवल अंतिम होगा।

आप देख सकते हैं इस यह कैसे काम करता के वर्णन के लिए है, लेकिन यह एक अलग लाइन में कई बार के रूप में केवल मैच पर प्रिंट होगा के रूप में यह एक लाइन पर होता है।

आप [num]एक पंक्ति पर वें घटना को प्राप्त करने के लिए उसी रणनीति का उपयोग कर सकते हैं । उदाहरण के लिए, यदि आप CONFIG मैच को प्रिंट करना चाहते थे, यदि यह एक लाइन पर तीसरा था:

sed '/\n/P;//d;s/CONFIG[[:alnum:]]*/\n&\n/3;D'

... हालांकि यह मानता है कि CONFIG तार प्रत्येक घटना के लिए कम से कम एक गैर-अल्फ़ान्यूमेरिक वर्ण द्वारा अलग किए जाते हैं।

मुझे लगता है - संख्या के लिए - यह भी काम करेगा:

sed -n 's/[^0-9]\{1,\}/\n/g;s/\n*\(.*[0-9]\).*/\1/p

... दाहिने हाथ के बारे में पहले की तरह एक ही चेतावनी के साथ \n । यह एक भी पहले की तुलना में तेज होगा, लेकिन आमतौर पर, स्पष्ट रूप से लागू नहीं हो सकता है।

CONFIG चीज़ के लिए आप P;...;Dअपने पैटर्न के साथ ऊपर दिए गए लूप का उपयोग कर सकते हैं , या आप कर सकते हैं:

sed -n 's/[^C]*\(CONFIG[[:alnum:]]*\)\{0,1\}C\{0,1\}/\1\n/g;s/\(\n\)*/\1/g;/C/s/.$//p'

... जो अभी थोड़ा अधिक शामिल है और सही ढंग से sedसंदर्भ प्राथमिकता को क्रमबद्ध करके काम करता है । यह एक ही बार में सभी CONFIG मैचों को एक पंक्ति में अलग-थलग कर देता है - हालाँकि यह पहले जैसी ही धारणा बनाता है - कि प्रत्येक CONFIG मैच को कम से कम एक गैर-अल्फ़ान्यूमेरिक वर्ण द्वारा अलग किया जाएगा। GNU के साथ sedआप इसे लिख सकते हैं:

sed -En 's/[^C]*(CONFIG\w*)?C?/\1\n/g;s/(\n)*/\1/g;/C/s/.$//p'
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.