एन अंकों के समूहों के लिए grep कैसे करें, लेकिन n से अधिक नहीं?


33

मैं लिनक्स सीख रहा हूं, और मेरी एक चुनौती है कि मैं अपने दम पर हल करने में विफल होता हूं। यह रहा:

एक फ़ाइल से एक पंक्ति को पंक्तिबद्ध करें जिसमें एक पंक्ति में 4 संख्याएँ हैं लेकिन 4 से अधिक नहीं।

मुझे यकीन नहीं है कि यह कैसे होगा। मैं विशिष्ट संख्याओं के लिए खोज कर सकता हूं, लेकिन उनकी राशि एक स्ट्रिंग में नहीं।


2
एक पंक्ति की तरह 1234a12345प्रदर्शित होना चाहिए या नहीं?
एलियाह कगन

@ बुद्ध आपको अपने प्रश्न को एक उदाहरण के साथ समझाने की आवश्यकता है।
अविनाश राज

यदि संख्या स्थान से पहले या लाइन एंकर की शुरुआत और लाइन एंकर के एक स्थान या अंत के बाद है तो आप बस शब्द सीमाओं का उपयोग कर सकते हैं। \b\d{4}\b
अविनाश राज

1
यह सवाल स्पष्ट रूप से grep उपयोग के बारे में होने से नियमित अभिव्यक्ति के बारे में कुछ सवालों से अलग है । उबंटू में यूनिक्स यूटिलिटीज का उपयोग करने के बारे में सवाल, जैसे कि grep, sed और awk, को यहां हमेशा ठीक माना गया है। कभी-कभी लोग पूछते हैं कि गलत टूल के साथ नौकरी कैसे करें ; फिर संदर्भ की कमी एक बड़ी समस्या है, लेकिन यहां ऐसा नहीं है। यह ऑन-टॉपिक है, हमारे समुदाय के लिए उपयोगी, उत्तर देने के लिए पर्याप्त स्पष्ट है, और आगे के उत्तर को रोकने या इसे हटाने या माइग्रेशन की ओर धकेलने में कोई लाभ नहीं है। मैं इसे फिर से खोलने के लिए मतदान कर रहा हूं।
एलियाह कगन

1
आप लोगों का बहुत-बहुत धन्यवाद, मुझे नहीं पता था कि मुझे इतना फीडबैक मिलेगा। यह वह उत्तर है जिसकी मुझे तलाश थी: grep -E '(^ ​​| [^ 0-9]) [0-9] {4} ($। [^ 0-9])' फ़ाइल। कमांड को इस तरह एक स्ट्रिंग खींचने में सक्षम होना चाहिए (जो यह करता है): abc1234abcd99999
बुद्ध

जवाबों:


52

इस प्रश्न की व्याख्या करने के दो तरीके हैं; मैं दोनों मामलों को संबोधित करूंगा। आप लाइनें प्रदर्शित करना चाह सकते हैं:

  1. इसमें चार अंकों का एक क्रम होता है जो कि अंकों के किसी भी लंबे अनुक्रम का हिस्सा नहीं है, या
  2. इसमें चार अंकों का अनुक्रम होता है, लेकिन अंकों का कोई अनुक्रम नहीं होता (अलग से भी नहीं)।

उदाहरण के लिए, (1) प्रदर्शित होगा 1234a56789, लेकिन (2) नहीं होगा।


यदि आप उन सभी रेखाओं को प्रदर्शित करना चाहते हैं जिनमें चार अंकों का अनुक्रम होता है, जो कि अंकों के किसी भी लंबे अनुक्रम का हिस्सा नहीं है, तो एक तरीका:

grep -P '(?<!\d)\d{4}(?!\d)' file

यह पर्ल रेगुलर एक्सप्रेशंस का उपयोग करता है , जो कि Ubuntu grep( GNU grep ) के माध्यम से सपोर्ट करता है -P। यह पाठ की तरह मेल नहीं खाएगा 12345, और न ही इसका मिलान होगा 1234या 2345इसका हिस्सा होगा। लेकिन यह से मेल खाएगी 1234में 1234a56789

पर्ल नियमित अभिव्यक्तियों में:

  • \dकिसी भी अंक का मतलब है (यह कहने का छोटा तरीका है [0-9]या [[:digit:]])।
  • x{4}x4 बार मेल खाता है। ( { }वाक्यविन्यास पर्ल नियमित अभिव्यक्तियों के लिए विशिष्ट नहीं है; यह विस्तारित नियमित अभिव्यक्तियों grep -Eमें भी है।) तो \d{4}जैसा है वैसा ही है \d\d\d\d
  • (?<!\d)एक शून्य-चौड़ाई नकारात्मक रूप-दर्शन के पीछे है। इसका मतलब है "जब तक पहले नहीं \d।"
  • (?!\d)शून्य-चौड़ाई वाला नकारात्मक रूप-आगे मुखर है। इसका मतलब है "जब तक पीछा नहीं किया जाता है \d।"

(?<!\d)और (?!\d)चार अंकों के अनुक्रम के बाहर पाठ से मेल नहीं खाते; इसके बजाय, वे (जब एक साथ उपयोग किए जाते हैं) चार अंकों के अनुक्रम को अपने आप से मिलान होने से रोकते हैं यदि यह अंकों के लंबे अनुक्रम का हिस्सा है।

सिर्फ लुक-पीछे या सिर्फ लुक-फॉरवर्ड का उपयोग करना अपर्याप्त है, क्योंकि सबसे दाहिने या बाएं चार अंकों के बाद भी मिलान किया जाएगा।

लुक-बैक और लुक-फॉरवर्ड अभिकथन का उपयोग करने का एक फायदा यह है कि आपका पैटर्न केवल चार अंकों के अनुक्रम से मेल खाता है, न कि आसपास के पाठ से। रंग हाइलाइटिंग ( --colorविकल्प के साथ ) का उपयोग करते समय यह सहायक होता है ।

ek@Io:~$ grep -P '(?<!\d)\d{4}(?!\d)' <<< 12345abc789d0123e4
12345abc789d0123e4

उबंटू में डिफ़ॉल्ट रूप से, प्रत्येक उपयोगकर्ता alias grep='grep --color=auto'अपनी ~.bashrcफ़ाइल में है । तो तुम जब तुम एक साधारण के साथ शुरू कमांड चलाएँ स्वचालित रूप से प्रकाश डाला रंग प्राप्त grep(यह तब होता है जब उपनाम का विस्तार कर रहे हैं) और मानक आउटपुट है एक टर्मिनल (यह क्या है के लिए चेक)। माचिस को आमतौर पर लाल रंग की छाया ( सिंदूर के करीब ) में हाइलाइट किया जाता है , लेकिन मैंने इसे इटैलिकाइज़्ड बोल्ड में दिखाया है। यहाँ एक स्क्रीनशॉट है:--color=auto
आउटपुट के रूप में 12345abc789d0123e4 के साथ उस grep कमांड को दिखाने वाला स्क्रीनशॉट, 0123 लाल रंग में हाइलाइट किया गया है।

और आप grepकेवल प्रिंट से मेल खाते हुए टेक्स्ट बना सकते हैं , न कि पूरी लाइन के साथ -o:

ek@Io:~$ grep -oP '(?<!\d)\d{4}(?!\d)' <<< 12345abc789d0123e4
0123

अल्टरनेटिव वे, विदाउट लुक-बिहाइंड और लुक-अहेड असेसरीज

हालाँकि, यदि आप:

  1. एक ऐसी कमांड की आवश्यकता है जो उन प्रणालियों पर भी चलेगी जहां grepसमर्थन नहीं है -Pया अन्यथा पर्ल नियमित अभिव्यक्ति का उपयोग नहीं करना चाहते हैं, और
  2. विशेष रूप से चार अंकों से मेल खाने की ज़रूरत नहीं है - जो आमतौर पर मामला है यदि आपका लक्ष्य बस मैच युक्त लाइनें प्रदर्शित करना है, और
  3. एक समाधान के साथ ठीक हैं जो थोड़ा कम सुरुचिपूर्ण है

... तो आप इसके बजाय एक विस्तारित नियमित अभिव्यक्ति के साथ इसे प्राप्त कर सकते हैं :

grep -E '(^|[^0-9])[0-9]{4}($|[^0-9])' file

यह चार अंकों और गैर-अंकीय चरित्र से मेल खाता है - या रेखा के आरंभ या अंत में - उनके आसपास। विशेष रूप से:

  • [0-9]किसी भी अंक से मेल खाता है (जैसे [[:digit:]], या \dपर्ल नियमित अभिव्यक्तियों में) और {4}इसका अर्थ है "चार बार।" तो [0-9]{4}चार अंकों के क्रम से मेल खाता है।
  • [^0-9]मैचों के 0माध्यम से वर्णों की श्रेणी में नहीं है 9। यह [^[:digit:]](या \D, पर्ल नियमित अभिव्यक्तियों में) के बराबर है ।
  • ^, जब यह [ ]कोष्ठक में प्रकट नहीं होता है , एक पंक्ति की शुरुआत से मेल खाता है। इसी तरह, $एक पंक्ति के अंत से मेल खाता है।
  • |साधन या कोष्ठक समूहन के लिए हैं (जैसे बीजगणित में)। तो (^|[^0-9])लाइन की शुरुआत या एक गैर-अंक चरित्र से ($|[^0-9])मेल खाता है , जबकि रेखा के अंत या एक गैर-अंक चरित्र से मेल खाता है।

तो मैच केवल चार अंकों वाले अनुक्रम में होते हैं ( [0-9]{4}) जो एक साथ होता है:

  • लाइन की शुरुआत में या एक गैर-अंक ( (^|[^0-9])), और से पहले
  • पंक्ति के अंत में या एक गैर-अंक ( ($|[^0-9])) के बाद।

यदि, दूसरी ओर, आप उन सभी पंक्तियों को प्रदर्शित करना चाहते हैं जिनमें चार अंकों का अनुक्रम होता है, लेकिन चार अंकों से अधिक का कोई अनुक्रम नहीं होता है (यहां तक ​​कि एक और जो केवल चार अंकों के दूसरे अनुक्रम से अलग होता है), तो वैचारिक रूप से आपके लक्ष्य उन पंक्तियों को खोजना है जो एक पैटर्न से मेल खाती हैं, लेकिन दूसरी नहीं।

इसलिए, भले ही आप यह जानते हों कि इसे एकल पैटर्न के साथ कैसे किया जाता है, मैं मैट के दूसरे सुझाव की तरह कुछ का उपयोग करने का सुझाव दूंगा , grepदो पैटर्न के लिए अलग-अलग।

ऐसा करते समय आपको पर्ल रेगुलर एक्सप्रेशंस के किसी भी उन्नत फीचर्स से दृढ़ता से लाभ नहीं होता है, इसलिए हो सकता है कि आप उनका उपयोग न करना पसंद करें। लेकिन उपरोक्त शैली को ध्यान में रखते हुए, यहाँ मैट समाधान का उपयोग छोटा \d(और ब्रेसिज़) के स्थान पर किया गया है [0-9]:

grep -P '\d{4}' file | grep -Pv '\d{5}'

चूंकि यह उपयोग करता है [0-9], मैट का तरीका अधिक पोर्टेबल है - यह उन प्रणालियों पर काम करेगा जहां grepपर्ल नियमित अभिव्यक्ति का समर्थन नहीं करता है। यदि आप इसके बजाय [0-9](या [[:digit:]]) का उपयोग करते हैं \d, लेकिन उपयोग करना जारी रखते हैं { }, तो आपको मैट के तरीके की पोर्टेबिलिटी थोड़ी अधिक संक्षिप्त रूप से मिलती है:

grep -E '[0-9]{4}' file | grep -Ev '[0-9]{5}'

वैकल्पिक तरीका, एक एकल पैटर्न के साथ

यदि आप वास्तव में एक grepआदेश पसंद करते हैं कि

  1. एक नियमित अभिव्यक्ति का उपयोग करता है (दो grepएस पाइप से अलग नहीं किया जाता है , ऊपर के रूप में)
  2. उन रेखाओं को प्रदर्शित करने के लिए जिनमें चार अंकों का कम से कम एक अनुक्रम होता है,
  3. लेकिन पांच (या अधिक) अंकों का कोई अनुक्रम नहीं,
  4. और आपको पूरी रेखा से मेल खाने में कोई आपत्ति नहीं है, न कि केवल अंक (आप शायद यह बुरा नहीं मानते)

... तो आप उपयोग कर सकते हैं:

grep -Px '(\d{0,4}\D)*\d{4}(\D\d{0,4})*' file

-xझंडा बनाता है grepकेवल लाइनों को प्रदर्शित जहां पूरे लाइन मैचों (बजाय किसी भी लाइन युक्त एक मैच)।

मैंने एक पर्ल रेगुलर एक्सप्रेशन का उपयोग किया है क्योंकि मुझे लगता है कि इस मामले में संक्षिप्तता \dऔर \Dस्पष्टता बढ़ जाती है। लेकिन अगर आप जहां सिस्टम के लिए कुछ पोर्टेबल की जरूरत grepका समर्थन नहीं करता -Pहै, तो आप उन लोगों के साथ की जगह ले सकता [0-9]है और [^0-9](या के साथ [[:digit:]]और [^[:digit]]):

grep -Ex '([0-9]{0,4}[^0-9])*[0-9]{4}([^0-9][0-9]{0,4})*' file

इन नियमित अभिव्यक्तियों के काम करने का तरीका है:

  • बीच में, \d{4}या [0-9]{4}चार अंकों के एक क्रम से मेल खाता है। हमारे पास इनमें से एक से अधिक हो सकते हैं, लेकिन हमें कम से कम एक होना चाहिए।

  • बाईं ओर, (\d{0,4}\D)*या ([0-9]{0,4}[^0-9])*शून्य या अधिक से मेल खाता है ( *) गैर-अंक के बाद चार अंकों से अधिक नहीं के उदाहरण। शून्य अंक (यानी, कुछ भी नहीं) "चार अंकों से अधिक नहीं" के लिए एक संभावना है। यह (a) खाली स्ट्रिंग या (b) किसी भी स्ट्रिंग को गैर-अंक में समाप्त करता है और जिसमें चार अंकों से अधिक का कोई अनुक्रम नहीं होता है।

    चूँकि तुरंत केंद्रीय \d{4}(या [0-9]{4}) के बाईं ओर का पाठ रिक्त होना चाहिए या एक गैर-अंक के साथ समाप्त होना चाहिए, यह केंद्रीय \d{4}को चार अंकों के मिलान से रोकता है जिनके पास बाईं ओर एक और (पांचवां) अंक होता है।

  • दाईं ओर, (\D\d{0,4})*या ([^0-9][0-9]{0,4})*शून्य या अधिक ( *) एक गैर-अंक के उदाहरणों का अनुसरण करते हैं, जिसके बाद चार अंकों से अधिक नहीं (जो पहले की तरह, चार, तीन, दो, एक, या यहां तक ​​कि कोई भी नहीं हो सकता है)। यह (a) खाली स्ट्रिंग या (b) किसी भी स्ट्रिंग की शुरुआत गैर-अंक में करता है और जिसमें चार अंकों से अधिक का कोई अनुक्रम नहीं होता है।

    चूँकि तुरंत केंद्रीय \d{4}(या [0-9]{4}) के दाईं ओर पाठ खाली होना चाहिए या एक गैर-अंक के साथ शुरू होना चाहिए, यह केंद्रीय \d{4}को चार अंकों के मिलान से रोकता है जिनके पास उनके दाईं ओर एक और (पांचवां) अंक होता है।

यह सुनिश्चित करता है कि चार-अंकीय अनुक्रम कहीं मौजूद है, और यह कि पाँच या अधिक अंकों का कोई भी क्रम कहीं भी मौजूद नहीं है।

इसे इस तरह करना बुरा या गलत नहीं है। लेकिन शायद इस विकल्प पर विचार करने का सबसे महत्वपूर्ण कारण यह है कि यह उपर्युक्त और मैट के उत्तर के रूप में इसके बजाय (या समान) के उपयोग के लाभ को स्पष्ट करता है ।grep -P '\d{4}' file | grep -Pv '\d{5}'

इस तरह से, यह स्पष्ट है कि आपका लक्ष्य उन पंक्तियों का चयन करना है जिनमें एक चीज होती है, लेकिन दूसरी नहीं। इसके अलावा वाक्य रचना सरल है (इसलिए यह कई पाठकों / अनुरक्षकों द्वारा अधिक तेज़ी से समझा जा सकता है)।


9

यह आपको एक पंक्ति में 4 नंबर दिखाएगा लेकिन अधिक नहीं

grep '[0-9][0-9][0-9][0-9][^0-9]' file

नोट ^ का मतलब यह नहीं है

इसके साथ एक समस्या है, हालांकि मुझे यकीन नहीं है कि कैसे ठीक किया जाए ... यदि संख्या रेखा का अंत है तो यह दिखाई नहीं देगा।

हालांकि यह बदसूरत संस्करण उस मामले के लिए काम करेगा

grep '[0-9][0-9][0-9][0-9]' file | grep -v [0-9][0-9][0-9][0-9][0-9]

उफ़, नहीं होना चाहिए egrep - मैंने इसे संपादित किया है
मैट

2
पहला गलत है - यह पाता है a12345b, क्योंकि यह मेल खाता है 2345b
वोल्कर साइगेल

0

यदि grepनियमित अभिव्यक्ति का समर्थन नहीं करता है ( -P), निम्नलिखित शेल कमांड का उपयोग करें:

grep -w "$(printf '[0-9]%.0s' {1..4})" file

जहां printf '[0-9]%.0s' {1..4}4 गुना उत्पादन होगा [0-9]। यह विधि उपयोगी है, जब आपको लंबे अंक मिले हैं और आप पैटर्न को दोहराना नहीं चाहते हैं (बस 4देखने के लिए अपने अंकों की संख्या के साथ बदलें )।

प्रयोग -wकरने से पूरे शब्द दिखेंगे। हालाँकि यदि आप अल्फ़ान्यूमेरिक स्ट्रिंग्स में रुचि रखते हैं, जैसे कि 1234a, तो [^0-9]पैटर्न के अंत में जोड़ें , उदा

grep "$(printf '[0-9]%.0s' {1..4})[^0-9]" file

उपयोग करना $()मूल रूप से एक कमांड प्रतिस्थापन है । पैटर्न कैसे दोहराता है यह देखने के लिए इस पोस्ट को देखें printf


0

आप fileअपने सिस्टम में वास्तविक फ़ाइल नाम के साथ प्रतिस्थापित करके कमांड के नीचे की कोशिश कर सकते हैं :

grep -E '(^|[^0-9])[0-9]{4}($|[^0-9])' file

आप इस ट्यूटोरियल को grep कमांड के अधिक उपयोगों के लिए भी देख सकते हैं ।

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