एक पंक्ति के प्रारंभ या मध्य में पैटर्न के लिए Grep


9

मैं यह कहकर शुरू करूंगा कि मुझे लगता है कि यह समस्या थोड़ी कम निर्दोष है जितना लगता है।

मुझे क्या करने की आवश्यकता है: पाथ पर्यावरण चर के भीतर एक फ़ोल्डर की जांच करें। यह शुरुआत में या कहीं के बाद हो सकता है। मुझे बस यह सत्यापित करने की आवश्यकता है कि वह फ़ोल्डर वहां मौजूद है।

मेरी समस्या का उदाहरण - आइए उपयोग करते हैं /opt/gnome


SCENARIO 1: फ़ोल्डर PATH की शुरुआत में नहीं है

# echo "$PATH"
/sbin:/usr/sbin:/opt/gnome:/var/opt/gnome

# echo "$PATH" | grep ":/opt/gnome"
/sbin:/usr/sbin:/opt/gnome:/var/opt/gnome

ध्यान दें कि grep को पर्याप्त विशिष्ट होना चाहिए ताकि यह पकड़ में न आए /var/opt/gnome। इसलिए बृहदान्त्र।


SCENARIO 2: फ़ोल्डर PATH की शुरुआत में है।

# echo "$PATH"
/opt/gnome:/sbin:/usr/sbin:/var/opt/gnome

# echo "$PATH" | grep "^/opt/gnome"
/opt/gnome:/sbin:/usr/sbin:/var/opt/gnome

यह मेरी समस्या है - मुझे इस फ़ोल्डर के साथ कॉलन या स्टार्ट-ऑफ लाइन की खोज करने की आवश्यकता है। मैं क्या करना चाहूंगा इन दो कोष्ठक अभिव्यक्तियों में से एक है:

# echo $PATH | grep "[^:]/opt/gnome"
# echo $PATH | grep "[:^]/opt/gnome"

लेकिन [^और [:अपने स्वयं के अर्थ है। इसलिए, ऊपर दिए गए दो आदेश काम नहीं करते हैं।

वहाँ एक तरह से मैं एक आदेश में इन दो परिदृश्यों के लिए grep कर सकता है?


ध्यान दें कि कोस्टास के जवाब पर गिल्स की टिप्पणी प्रश्न पर भी लागू होती है: चूंकि आप के लिए नहीं कर रहे हैं , /opt/gnome:या /opt/gnome$आप पाएंगे /opt/gnome-fooया /opt/gnome/bar
स्कॉट

@ स्थिति - जब तक आप अपने मैच में हस्तक्षेप करने वाले स्थान को शामिल करते हैं, तब तक आप हमेशा इस तरह की जटिलताओं के बिना लाइन के सिर और पूंछ पर किसी भी स्ट्रिंग को लंगर डाल सकते हैं। ठीक उसी तरह जैसेgrep '^\(any number of other matches:*:\)*my match\(:.*\)*$'
mikeserv

जवाबों:


10

यदि आप PATHपर्यावरण चर की सामग्री की जाँच कर रहे हैं , जैसा कि किसी फ़ाइल में किसी चीज़ की तलाश के विपरीत है, तो grepगलत उपकरण है। इसे खोल में करना आसान (और तेज़ और यकीनन अधिक पठनीय) है।

बैश में, ksh और zsh:

if [[ :$PATH: = *:/opt/gnome:* ]]; then
 : # already there
else
  PATH=$PATH:/opt/gnome
fi

portably:

case :$PATH: in
  *:/opt/gnome:*) :;; # already there
  *) PATH=$PATH:/opt/gnome;;
esac

के :$PATH:बजाय के उपयोग पर ध्यान दें $PATH; इस तरह, घटक हमेशा खोज स्ट्रिंग में कॉलनों से घिरा होता है, भले ही वह शुरुआत या अंत में हो $PATH

यदि आप किसी फ़ाइल की एक पंक्ति के माध्यम से खोज कर रहे हैं, तो आप मिलान करने के लिए विस्तारित regexp (अर्थात आवश्यक grep -E) (^|:)/opt/gnome($|:)का उपयोग कर सकते हैं, /opt/gnomeलेकिन केवल यदि यह लाइन की शुरुआत में है या किसी कॉलोन का अनुसरण कर रहा है, और केवल तभी जब यह अंत में हो लाइन या एक बृहदान्त्र द्वारा पीछा किया।


8

आप केवल उपयोग करके विस्तारित नियमित अभिव्यक्तियों का उपयोग कर सकते हैं grep -E

यदि आप झूठी सकारात्मकता से बचना चाहते हैं तो आपको उस पथ के आरंभ और अंत का मिलान करना होगा जिसे आप खोजने का प्रयास कर रहे हैं।

शुरुआत में उदाहरण से मेल खाता है:

$ TEST=/opt/gnome:/sbin:/usr/sbin:/var/opt/gnome
$ echo $TEST | grep -E "(:|^)/opt/gnome(:|$)"
/opt/gnome:/sbin:/usr/sbin:/var/opt/gnome

बीच में उदाहरण से भी मेल खाता है:

$ TEST=/sbin:/usr/sbin:/opt/gnome:/var/opt/gnome
$ echo $TEST | grep -E "(:|^)/opt/gnome(:|$)"
/sbin:/usr/sbin:/opt/gnome:/var/opt/gnome

झूठी सकारात्मकता से बचना:

$ TEST="/home/bob/opt/gnome:/opt/gnome/somethingelse:/opt/gnome-beta"
$ echo $TEST | grep -E "(:|^)/opt/gnome(:|$)"

वहां कोई मैच नहीं।

कॉम्पैक्ट और सुरुचिपूर्ण। डेबियन 7 पर परीक्षण किया गया।


1
egrepपदावनत इस्तेमाल होता है grep -E: (स्रोत man grep)
Anthon

धन्यवाद, एक आकर्षण की तरह काम करता है! मैंने हालांकि इसका जवाब नहीं चुना, क्योंकि मुझे लगता है कि -w विकल्प थोड़ा अधिक सरल है। मूल रूप से मैंने जितनी कल्पना की थी, उससे भी अधिक सरल!
21

3
चेतावनी। -wविकल्प कुछ समस्या है। केवल अंकों, अक्षरों और अंडरस्कोर को "शब्द" माना जाता है। तो कुछ असामान्य लेकिन संभव आकर्षण इसे विफल बना देंगे। उदाहरण echo '/sbin:/usr/sbin:/var-/opt/gnome' | grep -w "/opt/gnome"और echo '/sbin:/usr/sbin:/var./opt/gnome' | grep -w "/opt/gnome"। जो गलत परिणाम देते हैं।
लुइस एंटोलिन कैनो

1
आप सही रास्ते पर हैं, लेकिन अभी भी झूठी सकारात्मकताएँ हैं /opt/gnome/somethingelse:।
गिल्स एसओ- बुराई को रोकें '

1
बिलकुल सही। हमें केवल अंत ही नहीं, स्पष्ट रूप से अंत की परवाह करनी चाहिए। मुझे लगता है कि यह समस्याओं को ठीक करता है echo "/home/bob/opt/gnome:/opt/gnome/somethingelse:/opt/gnome-beta" | grep -E "(:|^)/opt/gnome(:|$)"। उत्तर का संपादन।
लुइस एंटोलिन कैनो

7

यदि आप के लिए wed नहीं हैं grep, तो आप उपयोग कर सकते हैं awkऔर रिकॉर्ड को अलग कर सकते हैं:

awk 'BEGIN {RS=":"} /^\/opt\/gnome$/'

5

आप भी इस्तेमाल कर सकते हैं

echo "$PATH" | tr ':' '\n' | grep -x "/opt/gnome"

जो पथ-चर को अलग-अलग रेखाओं (प्रति पथ) में विभाजित करता है, इसलिए grep -xसटीक परिणामों की तलाश कर सकता है। यह निश्चित रूप से नुकसान है कि इसके लिए एक अतिरिक्त प्रक्रिया की आवश्यकता है tr। और यह तब काम नहीं करेगा जब एक फ़ोल्डर नाम में PATHnewline वर्ण हों।


2

मुझे नहीं पता कि यह उत्तर के लिए पर्याप्त है लेकिन

grep -w "/opt/gnome"

आपकी आवश्यकता को पूरा करेगा।

echo '/sbin:/usr/sbin:/opt/gnome:/var/opt/gnome' | grep -w "/opt/gnome" -o
/opt/gnome
echo '/opt/gnome:/sbin:/usr/sbin:/var/opt/gnome' | grep -w "/opt/gnome" -o
/opt/gnome

परंतु

echo '/opt/gnome:/sbin:/usr/sbin:/var/opt/gnome' | grep "/opt/gnome" -o
/opt/gnome
/opt/gnome

यह पूरी तरह से काम करता है क्योंकि कॉलोन गैर-शब्द अक्षर हैं। धन्यवाद!
जेम्सएल

@ Sman865 अन्य कारण है: क्योंकि /शब्द का एक हिस्सा नहीं है, लेकिन rहै।
कोस्टा

2
चेतावनी। जैसा कि मैंने अपने जवाब पर टिप्पणी में कहा था। एक निर्देशिका नाम के लिए कानूनी वर्ण हैं जो गैर-शब्द वर्ण हैं। जिसके चलते गलत परिणाम आए। किसी निर्देशिका नाम को समाप्त करना सामान्य नहीं है - लेकिन ऐसा हो सकता है।
लुइस एंटोलिन कैनो

4
@ Sman865 गलत सकारात्मक: /opt/gnome-beta, /home/bob/opt/gnome, ...
गाइल्स 'तथाकथित बंद किया जा रहा है बुराई'

काम नहीं करने का मामला: grep -w /usr/local -o <<< /usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games------/usr/local /usr/local /usr/local
पाबौक

0

चयन करने के लिए /opt/gnomeगैर-शब्द पात्रों से घिरा हुआ (नई लाइनों, :, /, आदि) यह एक कोशिश:

grep '\B/opt/gnome'

0

आप इसे मज़बूती से और कम मेहनत के साथ कर सकते हैं grep। आप उन एक्सटेंशनों का लाभ उठा सकते हैं जो व्यापक रूप से उपलब्ध हैं और जिनके बीच से कई समाधान पहले ही पेश किए जा चुके हैं, लेकिन मूल रीगेक्स के साथ भी यह आसानी से किया जाता है, हालांकि यह पहली बार में सहज नहीं हो सकता है।

मूल रेगेक्स के साथ - और इसलिए grep- आपके पास हमेशा दो विश्वसनीय एंकर हैं - लाइन का सिर और पूंछ। आप लाइन पर इसके स्थान की परवाह किए बिना इन दोनों का मिलान कर सकते हैं:

grep '^\(ignore case, delimiter\)*match\(delimiter, ignore case\)*$'

grepलाइन के प्रमुख से \(grouped\)उपपरिवर्तनों की कई घटनाओं के रूप में मेल खाएगा क्योंकि यह आपके सीमांकक के बाद आपका स्पष्ट मिलान और उसके मैच की पूंछ से उसी तरह लाइन के पूंछ तक मुठभेड़ करना होगा। आपकी स्पष्ट मैच दिखाया नहीं जाता तो स्पष्ट रूप से यह असफल और कुछ भी नहीं प्रिंट होगा।

और इसलिए आप कर सकते हैं, उदाहरण के लिए:

grep '^\(.*:\)*/opt/gnome\(:.*\)*$'

अपने आप को देखो:

grep '^\(.*:\)*/opt/gnome\(:.*\)*$
' <<\INPUT
/opt/gnome-beta
/opt/gnome
/home/bob/opt/gnome
:/opt/gnome:
/home/bob/opt/gnome:/opt/gnome:/opt/gnome-beta
/opt-gnome-beta
/opt/gnomenot::::/opt/gnome
INPUT

आउटपुट

/opt/gnome
:/opt/gnome:
/home/bob/opt/gnome:/opt/gnome:/opt/gnome-beta
/opt/gnomenot::::/opt/gnome

0

आपने एक किनारे मामले पर ध्यान दिया है ... आप लाइन की शुरुआत में a: की स्पष्टता को मजबूर करके इससे बच सकते हैं:

 echo ":$PATH" | grep ":/opt/gnome"

या यदि मार्ग सटीक है तो यह सुनिश्चित करने के लिए अंत में एक को भी जोड़ें:

 echo ":${PATH}:" | grep ":/opt/gnome:"
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.