पैटर्न के बाद सामग्री के लिए grep कैसे करें?


81

उदाहरण के लिए, एक फ़ाइल दी:

potato: 1234
apple: 5678
potato: 5432
grape: 4567
banana: 5432
sushi: 56789

मैं उन सभी लाइनों के लिए grep करना चाहूंगा जो शुरू होती हैं, potato:लेकिन केवल उन संख्याओं को पाइप करती हैं जो अनुसरण करती हैं potato:। तो उपरोक्त उदाहरण में, आउटपुट होगा:

1234
5432

मैं उसे कैसे कर सकता हूँ?

जवाबों:


113
grep 'potato:' file.txt | sed 's/^.*: //'

grepकिसी भी पंक्ति को देखता है जिसमें स्ट्रिंग शामिल है potato:, फिर, इन पंक्तियों में से प्रत्येक के लिए, पंक्ति की शुरुआत से ( ) स्थानापन्न sed( s///- स्थानापन्न) किसी भी वर्ण ( .*) ^अनुक्रम के अंतिम घटना तक :(खाली स्थान के बाद बृहदान्त्र) होता है स्ट्रिंग ( s/...//- दूसरे भाग के साथ पहले भाग को प्रतिस्थापित करें, जो खाली है)।

या

grep 'potato:' file.txt | cut -d\   -f2

इसमें शामिल प्रत्येक पंक्ति के लिए potato:, cutअंतरिक्ष द्वारा सीमांकित कई क्षेत्रों में लाइन को विभाजित करेगा ( -d\- d= सीमांकक, \= बच गया अंतरिक्ष वर्ण, कुछ ऐसा -d" "भी काम किया होगा) और प्रत्येक ऐसी रेखा के दूसरे क्षेत्र को प्रिंट करें ( -f2)।

या

grep 'potato:' file.txt | awk '{print $2}'

इसमें शामिल प्रत्येक पंक्ति के लिए potato:, awkदूसरे फ़ील्ड ( print $2) को प्रिंट करेगा जो रिक्त स्थान द्वारा डिफ़ॉल्ट रूप से सीमांकित है।

या

grep 'potato:' file.txt | perl -e 'for(<>){s/^.*: //;print}'

सभी पंक्तियाँ जिनमें potato:एक इनलाइन ( -e) पर्ल स्क्रिप्ट भेजी जाती है stdin, जो इन पंक्तियों में से प्रत्येक के लिए लेती है , फिर, इन पंक्तियों में से प्रत्येक के लिए, पहले प्रतिस्थापन के समान ही प्रतिस्थापन करती है, फिर उसे प्रिंट करती है।

या

awk '{if(/potato:/) print $2}' < file.txt

फ़ाइल के माध्यम से भेजा जाता है stdin( फ़ाइल < file.txtकी सामग्री stdinको बाईं ओर कमांड के माध्यम से भेजता है ) एक awkस्क्रिप्ट के लिए है, जिसमें प्रत्येक पंक्ति के लिए है potato:( जिसमें if(/potato:/)नियमित अभिव्यक्ति /potato:/वर्तमान रेखा से मेल खाती है, तो सही है ), दूसरे फ़ील्ड को प्रिंट करता है, जैसा कि वर्णित है। ऊपर।

या

perl -e 'for(<>){/potato:/ && s/^.*: // && print}' < file.txt

फ़ाइल को एक पर्ल स्क्रिप्ट के माध्यम से भेजा जाता है stdin( < file.txtऊपर देखें), जो ऊपर दी गई एक ही तरह से काम करता है, लेकिन इस बार यह भी सुनिश्चित करता है कि प्रत्येक पंक्ति में स्ट्रिंग हो potato:( /potato:/एक नियमित अभिव्यक्ति है जो वर्तमान रेखा से मेल खाती है potato:और, यदि यह करता है ( &&), फिर ऊपर वर्णित नियमित अभिव्यक्ति को लागू करने के लिए आगे बढ़ता है और परिणाम प्रिंट करता है)।


3
दो प्रक्रियाओं और एक पाइप के लिए कोई ज़रूरत नहीं है। मैं के लिए जाना होगा awk '$1 ~ /potato/ { print $2 }' file.txt
मुसीफिल

2
जाग एक और अधिक मुहावरेदार होगाawk '/potato:/ {print $2}'
बेंजामिन डब्ल्यू।

पर्ल स्क्रिप्ट से लाभ हो सकता हैperl -pe
ट्रिपल

60

या regex अभिकथन का उपयोग करें: grep -oP '(?<=potato: ).*' file.txt


4
मैंने ऊपर दिए गए स्वीकृत उत्तर में से कुछ एक-लाइनरों की कोशिश की, लेकिन मुझे लगता है कि यह उत्तर अधिक सटीक रूप से प्रश्न हल करता है।
जेक 8

3
कुछ स्पष्टीकरण: विकल्प का -oअर्थ है लाइन के मिलान वाले भाग को प्रिंट करना। जबकि -Pएक पर्ल-संगत नियमित अभिव्यक्ति को संक्रमित करता है, जो कि रेगेक्स के लिए एक सकारात्मक खोज के रूप में होता है (?<=string)
सर्ज स्ट्रोबोबांट

9
sed -n 's/^potato:[[:space:]]*//p' file.txt

एक ग्रीप को एक प्रतिबंधित सैड के रूप में, या एक सामान्यीकृत ग्रीप के रूप में सेड के बारे में सोच सकते हैं। इस मामले में, सेड एक अच्छा, हल्का उपकरण है जो वह करता है जो आप चाहते हैं - हालांकि, निश्चित रूप से, इसे करने के लिए कई अन्य उचित तरीके मौजूद हैं।


2

यह प्रत्येक मैच के बाद सब कुछ प्रिंट करेगा, केवल उसी लाइन पर:

perl -lne 'print $1 if /^potato:\s*(.*)/' file.txt

यह वही करेगा, इसके अलावा यह बाद की सभी पंक्तियों को भी मुद्रित करेगा:

perl -lne 'if ($found){print} elsif (/^potato:\s*(.*)/){print $1; $found++}' file.txt

इन कमांड-लाइन विकल्पों का उपयोग किया जाता है:

  • -n इनपुट फ़ाइल की प्रत्येक पंक्ति के चारों ओर लूप
  • -l प्रसंस्करण से पहले नई लिंक हटाता है, और बाद में उन्हें वापस जोड़ता है
  • -e पर्ल कोड निष्पादित करें

2
grep -Po 'potato:\s\K.*' file

-P नियमित अभिव्यक्ति पर्ल का उपयोग करने के लिए

-o केवल मैच का उत्पादन करने के लिए

\s के बाद अंतरिक्ष मैच के लिए potato:

\K मैच को छोड़ना है

.* बाकी स्ट्रिंग से मिलान करने के लिए


1

आप grep का उपयोग कर सकते हैं, अन्य उत्तर के रूप में। लेकिन आपको grep, awk, sed, perl, cut, या किसी भी बाहरी टूल की आवश्यकता नहीं है। आप इसे शुद्ध बैश के साथ कर सकते हैं।

यह कोशिश करो (अर्धविराम वहाँ हैं कि आप इसे एक पंक्ति में डाल सकें):

$ while read line;
  do
    if [[ "${line%%:\ *}" == "potato" ]];
    then
      echo ${line##*:\ };
    fi;
  done< file.txt

## सामने से $ लाइन में ":" का सबसे लंबा मैच हटाने के लिए बैश बताता है।

$ while read line; do echo ${line##*:\ }; done< file.txt
1234
5678
5432
4567
5432
56789

या यदि आप मूल्य के बजाय कुंजी चाहते थे, तो %% अंत से $ लाइन में ":" के सबसे लंबे मैच को हटाने के लिए बैश बताता है।

$ while read line; do echo ${line%%:\ *}; done< file.txt
potato
apple
potato
grape
banana
sushi

पर विभाजित करने का विकल्प ": \" है, क्योंकि अंतरिक्ष वर्ण को बैकस्लैश से बच जाना चाहिए।

आप linux प्रलेखन परियोजना में इनकी तरह अधिक पा सकते हैं ।


while readबहुत धीमी है; बाहरी उपयोगिता का उपयोग करना वास्तव में तब तक बहुत तेज़ होगा जब तक कि आप बफर आई / ओ के साथ एक का चयन करते हैं (अर्थात व्यावहारिक रूप से इस उत्तर में उल्लिखित कोई भी, और कई अन्य)।
ट्रिपल

इसके अलावा, आपको read -rतब तक उपयोग करना चाहिए जब तक कि आपको POSIX से पहले कुछ विशेष रूप से पेसकी विरासत व्यवहार की आवश्यकता न हो।
ट्रिपल

0

आधुनिक BASH के पास नियमित अभिव्यक्ति के लिए समर्थन है:

while read -r line; do
  if [[ $line =~ ^potato:\ ([0-9]+) ]]; then
    echo "${BASH_REMATCH[1]}"
  fi
done
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.