मल्टी लाइन grep कैसे करें


15

आप दो पंक्तियों पर दिखाई देने वाले पाठ के लिए एक grep कैसे करेंगे?

उदाहरण के लिए:

pbsnodes एक कमांड है जो मैं उपयोग करता हूं जो एक लिनक्स क्लस्टर का उपयोग करता है

root$ pbsnodes
node1
    state = free
    procs = 2
    bar = foobar

node2
    state = free
    procs = 4
    bar = foobar

node3
    state = busy
    procs = 8
    bar = foobar

मैं ऐसे प्रॉक्स की संख्या निर्धारित करना चाहता हूं जो नोड्स से मेल खाते हैं जो राज्य में 'मुक्त' हैं। अब तक मैं "प्रॉपर की संख्या" और "फ्री स्टेट में नोड्स" निर्धारित करने में सक्षम रहा हूं, लेकिन मैं उन्हें एक कमांड में संयोजित करना चाहता हूं जो सभी फ्री प्रॉक्स दिखाता है।

उपरोक्त उदाहरण में, सही उत्तर 6 (2 + 4) होगा।

जो मेरे पास है

root$ NUMBEROFNODES=`pbsnodes|grep 'state = free'|wc -l`
root$ echo $NUMBEROFNODES
2

root$ NUMBEROFPROCS=`pbsnodes |grep "procs = "|awk  '{ print $3 }' | awk '{ sum+=$1 } END { print sum }'`
root$ echo $NUMBEROFPROCS
14

मैं 'procs = x' पढ़ने वाली प्रत्येक पंक्ति को कैसे खोज सकता हूं, लेकिन केवल यदि इसके ऊपर की रेखा 'राज्य = मुक्त' पढ़ती है?

जवाबों:


12

यदि डेटा हमेशा उस प्रारूप में होता है, तो आप बस इसे लिख सकते हैं:

awk -vRS= '$4 == "free" {n+=$7}; END {print n}'

( RS=मतलब रिकॉर्ड पैराग्राफ हैं )।

या:

awk -vRS= '/state *= *free/ && match($0, "procs *=") {
  n += substr($0,RSTART+RLENGTH)}; END {print n}'

5
$ pbsnodes
node1
    state = free
    procs = 2
    bar = foobar

node2
    state = free
    procs = 4
    bar = foobar

node3
    state = busy
    procs = 8
    bar = foobar
$ pbsnodes | grep -A 1 free
    state = free
    procs = 2
--
    state = free
    procs = 4
$ pbsnodes | grep -A 1 free | grep procs | awk '{print $3}'
2
4
$ pbsnodes | grep -A 1 free | grep procs | awk '{print $3}' | paste -sd+ 
2+4
$ pbsnodes | grep -A 1 free | grep procs | awk '{print $3}' | paste -sd+ | bc 
6

https://en.wikipedia.org/wiki/Pipeline_(Unix)


4

यहां इसका उपयोग करने का एक तरीका है pcregrep

$ pbsnodes | pcregrep -Mo 'state = free\n\s*procs = \K\d+'
2
4

उदाहरण

$ pbsnodes | \
    pcregrep -Mo 'state = free\n\s*procs = \K\d+' | \
    awk '{ sum+=$1 }; END { print sum }'
6

3

पर्ल के पैराग्राफ स्लर के लिए आपका आउटपुट फॉर्मेट प्राइमेड है:

pbsnodes|perl -n00le 'BEGIN{ $sum = 0 }
                 m{
                   state \s* = \s* free \s* \n 
                   procs \s* = \s* ([0-9]+)
                 }x 
                    and $sum += $1;
                 END{ print $sum }'

ध्यान दें

यह केवल इसलिए काम करता है क्योंकि पर्ल का "पैराग्राफ" का विचार गैर-रिक्त लाइनों का एक हिस्सा है जिसे एक या अधिक रिक्त लाइनों द्वारा अलग किया जाता है। यदि आपके पास nodeअनुभागों के बीच रिक्त लाइनें नहीं हैं , तो यह काम नहीं करेगा।

यह सभी देखें


3

यदि आपके पास एक निश्चित लंबाई का डेटा (एक रिकॉर्ड में लाइनों की संख्या का उल्लेख करते हुए निश्चित लंबाई) है, sedतो आप Nकमांड (कई बार) का उपयोग कर सकते हैं , जो पैटर्न स्थान के लिए अगली पंक्ति में मिलती है:

sed -n '/^node/{N;N;N;s/\n */;/g;p;}'

आपको आउटपुट देना चाहिए जैसे:

node1;state = free;procs = 2;bar = foobar
node2;state = free;procs = 4;bar = foobar
node3;state = busy;procs = 8;bar = foobar

चर रिकॉर्ड संरचना (उदाहरण के लिए एक खाली विभाजक रेखा के साथ) के लिए, आप शाखाएं कमांड का उपयोग कर सकते हैं tऔर b, लेकिन awkआपको अधिक आरामदायक तरीके से वहां पहुंचने की संभावना है।


3

GNU कार्यान्वयन grepदो तर्कों के साथ एक मैच से पहले ( -B) और बाद ( -A) को भी मुद्रित करने के लिए आता है । मैन पेज से स्निपेट:

   -A NUM, --after-context=NUM
          Print NUM lines of trailing context after matching lines.  Places a line containing  a  group  separator  (--)  between  contiguous  groups  of  matches.   With  the  -o  or
          --only-matching option, this has no effect and a warning is given.

   -B NUM, --before-context=NUM
          Print  NUM  lines  of  leading  context  before  matching  lines.   Places  a  line  containing  a group separator (--) between contiguous groups of matches.  With the -o or
          --only-matching option, this has no effect and a warning is given.

तो आपके मामले में, आपको state = freeनिम्न के लिए grep करना होगा और प्रिंट भी करना होगा । अपने प्रश्न से स्निपेट के साथ संयोजन करते हुए आप कुछ इस तरह पहुंचेंगे:

usr@srv % pbsnodes | grep -A 1 'state = free' | grep "procs = " | awk  '{ print $3 }' | awk '{ sum+=$1 } END { print sum }'
6

और थोड़ा छोटा:

usr@srv % pbsnodes | grep -A 1 'state = free' | awk '{ sum+=$3 } END { print sum }'
6

awkपैटर्न मिलान करता है; आपको इसकी आवश्यकता नहीं है grep: स्टीफन के उत्तर को
जेसनव्रीयन

ठीक है, sedपैटर्न मिलान भी करता है। तुम भी इस्तेमाल कर सकते हैं perl, या php, या जो भी भाषा आप पसंद करते हैं। लेकिन कम से कम सवाल का शीर्षक मल्टी लाइन grep के लिए पूछा ... ;-)
द्विगुणित

हां: लेकिन आप किसी awkभी तरह का उपयोग कर रहे थे ... :)
jasonwryan

0

... और यहाँ एक पर्ल समाधान है:

pbsnodes | perl -lne 'if (/^\S+/) { $node = $& } elsif ( /state = free/ ) { print $node }'

0

आप awk getlineकमांड का उपयोग कर सकते हैं :

$ pbsnodes | awk 'BEGIN { freeprocs = 0 } \
                  $1=="state" && $3=="free" { getline; freeprocs+=$3 } \
                  END { print freeprocs }'

से man awk :

   getline               Set $0 from next input record; set NF, NR, FNR.

   getline <file         Set $0 from next record of file; set NF.

   getline var           Set var from next input record; set NR, FNR.

   getline var <file     Set var from next record of file.

   command | getline [var]
                         Run command piping the output either into $0 or var, as above.

   command |& getline [var]
                         Run  command  as a co-process piping the output either into $0 or var, as above.  Co-processes are a
                         gawk extension.
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.