कैसे सीड, awk, या gawk का उपयोग केवल मुद्रित करने के लिए कैसे किया जाता है?


100

मैं बहुत से उदाहरण और मैन पेज देखता हूँ कि कैसे खोज, और जगह का उपयोग करने के लिए sed, awk, या gawk जैसी चीजों को किया जाता है।

लेकिन मेरे मामले में, मेरे पास एक नियमित अभिव्यक्ति है जिसे मैं एक विशिष्ट मूल्य निकालने के लिए एक पाठ फ़ाइल के खिलाफ चलाना चाहता हूं। मैं खोज और प्रतिस्थापन नहीं करना चाहता। इसे बैश से बुलाया जा रहा है। आइए एक उदाहरण का उपयोग करें:

उदाहरण नियमित अभिव्यक्ति:

.*abc([0-9]+)xyz.*

उदाहरण इनपुट फ़ाइल:

a
b
c
abc12345xyz
a
b
c

जितना सरल यह लगता है, मैं सही तरीके से sed / awk / gawk को कॉल करने का तरीका नहीं जान सकता। मैं जो करने की उम्मीद कर रहा था, वह मेरी बैश स्क्रिप्ट के भीतर से है:

myvalue=$( sed <...something...> input.txt )

मैंने जिन चीजों की कोशिश की है उनमें शामिल हैं:

sed -e 's/.*([0-9]).*/\\1/g' example.txt # extracts the entire input file
sed -n 's/.*([0-9]).*/\\1/g' example.txt # extracts nothing

10
वाह ... लोगों ने इस सवाल को वोट किया -1? क्या यह वास्तव में एक प्रश्न के अनुचित है?
स्टीफन

यह पूरी तरह से उचित लगता है, रेक्स और शक्तिशाली कमांड लाइन उपयोगिताओं जैसे कि sed / awk या vi, emacs या teco जैसे किसी भी संपादक का उपयोग करना कुछ ol 'एप्लीकेशन का उपयोग करने की तुलना में प्रोग्रामिंग की तरह अधिक हो सकता है। IMO यह SU से ज्यादा SO पर होता है।
Dereleased

शायद इसे वोट दिया गया था क्योंकि इसके प्रारंभिक रूप में यह स्पष्ट रूप से इसकी कुछ आवश्यकताओं को परिभाषित नहीं करता था। यह अभी भी नहीं है, जब तक कि आप ओपी की टिप्पणियों के जवाबों को नहीं पढ़ते हैं (एक मैं हटा दिया था जब चीजें नाशपाती के आकार की थीं)।
पेविअम

जवाबों:


42

मेरे sed(Mac OS X) के साथ काम नहीं किया +। मैंने *इसके बजाय कोशिश की और मैंने pप्रिंटिंग मैच के लिए टैग जोड़ा :

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

बिना कम से कम एक संख्यात्मक चरित्र के मिलान के लिए +, मैं उपयोग करूंगा:

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

धन्यवाद, इसने मेरे लिए काम किया साथ ही मैंने एक बार + के बजाय * का उपयोग किया।
स्टीफन

2
... और मैच को प्रिंट करने के लिए "पी" विकल्प, जिसके बारे में मुझे नहीं पता था। एक बार फिर धन्यवाद।
स्टीफन

2
मुझे भागना पड़ा +और फिर इसने मेरे लिए काम किया:sed -n 's/^.*abc\([0-9]\+\)xyz.*$/\1/p'
अगली सूचना तक रुक गया।

3
ऐसा इसलिए है क्योंकि आप आधुनिक आरई प्रारूप का उपयोग नहीं कर रहे हैं इसलिए + एक मानक चरित्र है और आपको {,} वाक्य रचना के साथ व्यक्त करना चाहिए। आप आधुनिक आरई प्रारूप को ट्रिगर करने के लिए उपयोग-ई sed विकल्प जोड़ सकते हैं। चेक करें re_format (7), विशेष रूप से DESCRIPTION developer.apple.com/library/mac/#documentation/Darwin/Reference/…
anddam

33

आप ऐसा करने के लिए sed का उपयोग कर सकते हैं

 sed -rn 's/.*abc([0-9]+)xyz.*/\1/gp'
  • -n परिणामी लाइन प्रिंट न करें
  • -rयह ऐसा करता है ताकि आपके पास कैप्चर ग्रुप पार्न्स से बच न सके ()
  • \1 कब्जा समूह मैच
  • /g वैश्विक मैच
  • /p परिणाम प्रिंट करें

मैंने अपने लिए एक उपकरण लिखा है जो इसे आसान बनाता है

rip 'abc(\d+)xyz' '$1'

3
यह अब तक का सबसे अच्छा, और सबसे अधिक समझाया गया उत्तर है!
निक रेमन

कुछ स्पष्टीकरण के साथ, यह समझना बेहतर है कि हमारे मुद्दे में क्या गलत है। धन्यवाद !
r4phG

17

मैं perlअपने लिए यह आसान बनाने के लिए उपयोग करता हूं। जैसे

perl -ne 'print $1 if /.*abc([0-9]+)xyz.*/'

यह पर्ल चलाता है, -nविकल्प पर्ल को STDIN से एक बार में एक पंक्ति में पढ़ने और कोड निष्पादित करने का निर्देश देता है। -eविकल्प को चलाने के लिए अनुदेश निर्दिष्ट करता है।

निर्देश पढ़ा गया रेखा पर एक रेगेक्सप चलाता है, और अगर यह ब्रैट्स के पहले सेट की सामग्री से प्रिंट करता है ( $1)।

आप ऐसा कर सकते हैं कि कई फ़ाइल नाम अंत में भी होंगे। जैसे

perl -ne 'print $1 if /.*abc([0-9]+)xyz.*/' example1.txt example2.txt


धन्यवाद, लेकिन हमारे पास पर्ल तक पहुंच नहीं है, यही वजह है कि मैं sed / awk / gawk के बारे में पूछ रहा था।
स्टीफन

5

यदि आपका संस्करण grepइसका समर्थन करता है, तो आप किसी भी लाइन के केवल भाग -oको प्रिंट करने के लिए विकल्प का उपयोग कर सकते हैं जो आपके regexp से मेल खाता है।

अगर नहीं तो यहाँ सबसे अच्छा sedमैं के साथ आ सकता है:

sed -e '/[0-9]/!d' -e 's/^[^0-9]*//' -e 's/[^0-9]*$//'

... जो बिना अंकों के हटाता / छोड़ता है और शेष रेखाओं के लिए, सभी प्रमुख और अनुगामी गैर-अंकीय वर्णों को हटा देता है। (मैं केवल अनुमान लगा रहा हूं कि आपका इरादा प्रत्येक पंक्ति से संख्या निकालने का है जिसमें एक है)।

कुछ इस तरह की समस्या:

sed -e 's/.*\([0-9]*\).*/&/' 

.... या

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

... यह है कि sedकेवल "लालची" मैच का समर्थन करता है ... तो पहले। * शेष पंक्ति से मेल खाएगा। जब तक हम एक गैर-लालची मैच को प्राप्त करने के लिए एक उपेक्षित चरित्र वर्ग का उपयोग कर सकते हैं ... या sedपर्ल-संगत या इसके एक्सटेंशन के अन्य एक्सटेंशन के साथ एक संस्करण , हम पैटर्न स्पेस (एक लाइन) से सटीक पैटर्न मैच नहीं निकाल सकते )।


आप अपनी दो sedआज्ञाओं को इस तरह से जोड़ सकते हैं :sed -n 's/[^0-9]*\([0-9]\+\).*/\1/p'
अगली सूचना तक रुके।

पहले grep पर -o विकल्प के बारे में नहीं पता था। जानकर अच्छा लगा। लेकिन यह पूरे मैच को प्रिंट करता है, न कि "(...)" को। इसलिए यदि आप "abc ([[: digit:]] +]] + xyz" पर मेल कर रहे हैं तो आपको "abc" और "xyz" के साथ-साथ अंक भी मिलते हैं।
स्टीफन

मुझे याद दिलाने के लिए धन्यवाद grep -o! मैं ऐसा करने की कोशिश कर रहा था sedऔर कुछ लाइनों पर कई मैच खोजने की मेरी जरूरत से जूझ रहा था । मेरा समाधान है stackoverflow.com/a/58308239/117471
ब्रूनो ब्रोंस्की

3

आप उपयोग कर सकते हैं awkके साथ match()कब्जा कर लिया समूह तक पहुँचने के लिए:

$ awk 'match($0, /abc([0-9]+)xyz/, matches) {print matches[1]}' file
12345

यह पैटर्न से मेल खाने की कोशिश करता है abc[0-9]+xyz। यदि ऐसा होता है, तो यह अपने स्लाइस को सरणी में संग्रहीत करता है, matchesजिसका पहला आइटम ब्लॉक है [0-9]+। चूँकि match() चरित्र स्थिति, या सूचकांक, जहाँ से वह सबस्ट्रिंग शुरू होता है (1, यदि यह स्ट्रिंग की शुरुआत में शुरू होता है) , तो यह printकार्रवाई को ट्रिगर करता है।


साथ grepआप एक बार देख-पीछे और देखो आगे का उपयोग कर सकते हैं:

$ grep -oP '(?<=abc)[0-9]+(?=xyz)' file
12345

$ grep -oP 'abc\K[0-9]+(?=xyz)' file
12345

यह पैटर्न की जाँच करता है [0-9]+जब यह भीतर होता है abcऔर xyzअंकों को प्रिंट करता है।


2

perl सबसे साफ वाक्यविन्यास है, लेकिन अगर आपके पास perl नहीं है (हमेशा नहीं, तो मैं समझता हूं), तो gawk और regex के घटकों का उपयोग करने का एकमात्र तरीका gensub सुविधा का उपयोग करना है।

gawk '/abc[0-9]+xyz/ { print gensub(/.*([0-9]+).*/,"\\1","g"); }' < file

सैंपल इनपुट फाइल का आउटपुट होगा

12345

नोट: gensub पूरे regex (// के बीच) की जगह लेता है, इसलिए आपको प्रतिस्थापन में संख्या से पहले और बाद में पाठ से छुटकारा पाने के लिए ([0-9] +) से पहले और बाद में * लगाना होगा।


2
यदि आप gawk का उपयोग करना चाहते हैं (या चाहते हैं) एक चतुर, व्यावहारिक समाधान। आपने इसे नोट किया है, लेकिन स्पष्ट होने के लिए: गैर-जीएनयू अवेक में गेंसब () नहीं है, और इसलिए यह इसका समर्थन नहीं करता है।
सिनकोडेनाडा

अच्छा! हालांकि, match()पकड़े गए समूहों तक पहुंचने के लिए इसका उपयोग करना सबसे अच्छा हो सकता है । इसके लिए मेरा जवाब देखें ।
फेडोरक्वी 'एसओ स्टॉप हर्टिंग'

1

यदि आप लाइनों का चयन करना चाहते हैं तो उन बिट्स को हटा दें जिन्हें आप नहीं चाहते हैं:

egrep 'abc[0-9]+xyz' inputFile | sed -e 's/^.*abc//' -e 's/xyz.*$//'

यह मूल रूप से उन पंक्तियों का चयन करता है जिन्हें आप चाहते हैं egrepऔर फिर sedसंख्या से पहले और बाद में बिट्स को अलग करने के लिए उपयोग करते हैं।

आप इसे यहां क्रिया में देख सकते हैं:

pax> echo 'a
b
c
abc12345xyz
a
b
c' | egrep 'abc[0-9]+xyz' | sed -e 's/^.*abc//' -e 's/xyz.*$//'
12345
pax> 

अपडेट: जाहिर है कि यदि आप वास्तविक स्थिति अधिक जटिल हैं, तो आरईएस मुझे संशोधित करने की आवश्यकता होगी। उदाहरण के लिए यदि आप हमेशा शुरुआत और अंत में शून्य या अधिक गैर-संख्यात्मक के भीतर एक ही संख्या दफनाते थे:

egrep '[^0-9]*[0-9]+[^0-9]*$' inputFile | sed -e 's/^[^0-9]*//' -e 's/[^0-9]*$//'

दिलचस्प ... तो एक जटिल नियमित अभिव्यक्ति को लागू करने और अभी क्या (...) अनुभाग में है वापस पाने का एक सरल तरीका नहीं है? क्योंकि जब मैं देखता हूं कि आपने पहले यहां grep के साथ क्या किया था, तो sed के साथ, हमारी वास्तविक स्थिति "abc" और "xyz" छोड़ने की तुलना में बहुत अधिक जटिल है। नियमित अभिव्यक्ति का उपयोग किया जाता है क्योंकि पाठ के दोनों ओर बहुत सारे अलग-अलग पाठ दिखाई दे सकते हैं।
स्टीफन

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

0

ओपी का मामला यह निर्दिष्ट नहीं करता है कि एक लाइन पर कई मैच हो सकते हैं, लेकिन Google ट्रैफ़िक के लिए, मैं इसके लिए एक उदाहरण जोड़ूंगा।

चूंकि ओपी की जरूरत एक पैटर्न से समूह निकालने की है, इसलिए grep -o2 पास की आवश्यकता होगी। लेकिन, मुझे अभी भी काम पाने का यह सबसे सहज तरीका लगता है।

$ cat > example.txt <<TXT
a
b
c
abc12345xyz
a
abc23451xyz asdf abc34512xyz
c
TXT

$ cat example.txt | grep -oE 'abc([0-9]+)xyz'
abc12345xyz
abc23451xyz
abc34512xyz

$ cat example.txt | grep -oE 'abc([0-9]+)xyz' | grep -oE '[0-9]+'
12345
23451
34512

चूंकि प्रोसेसर का समय मूल रूप से स्वतंत्र है, लेकिन मानव की पठनीयता अनमोल है, इसलिए मैं इस प्रश्न के आधार पर अपने कोड को रिफ्लेक्टर करता हूं, "अब से एक साल बाद, मैं क्या सोचने वाला हूं?" वास्तव में, कोड के लिए जिसे मैं सार्वजनिक रूप से या अपनी टीम के साथ साझा करने का इरादा रखता हूं, मैं यह भी man grepपता लगाने के लिए खुला रहूंगा कि लंबे विकल्प क्या हैं और उन लोगों के विकल्प हैं। इस तरह:grep --only-matching --extended-regexp


-1

आप इसे शेल के साथ कर सकते हैं

while read -r line
do
    case "$line" in
        *abc*[0-9]*xyz* ) 
            t="${line##abc}"
            echo "num is ${t%%xyz}";;
    esac
done <"file"

-3

जाग के लिए। मैं निम्नलिखित स्क्रिप्ट का उपयोग करूंगा:

/.*abc([0-9]+)xyz.*/ {
            print $0;
            next;
            }
            {
            /* default, do nothing */
            }

यह संख्यात्मक मान को आउटपुट नहीं करता है ([0-9+]), यह पूरी लाइन को आउटपुट करता है।
मार्क लकाटा

-3
gawk '/.*abc([0-9]+)xyz.*/' file

2
यह काम नहीं लगता है। यह मैच के बजाय पूरी लाइन को प्रिंट करता है।
स्टीफन

आपके नमूना इनपुट फ़ाइल में, वह पैटर्न पूरी रेखा है। सही??? यदि आप जानते हैं पैटर्न किसी विशिष्ट क्षेत्र में होने जा रहा है: $ 1, $ 2 का उपयोग आदि .. जैसे gawk '$ 1 ~ /.*abc([0-9]+)xyz.*/' फ़ाइल
ghostdog74
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.