วิธีการ grep หลายบรรทัด


15

คุณจะทำการ grep สำหรับข้อความที่ปรากฏในสองบรรทัดได้อย่างไร?

ตัวอย่างเช่น:

pbsnodes เป็นคำสั่งที่ฉันใช้ที่ส่งคืนการใช้ประโยชน์ของคลัสเตอร์ linux

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

node2
    state = free
    procs = 4
    bar = foobar

node3
    state = busy
    procs = 8
    bar = foobar

ฉันต้องการกำหนดจำนวนของ procs ที่ตรงกับโหนดที่อยู่ในสถานะ 'ว่าง' จนถึงตอนนี้ฉันสามารถระบุ "จำนวนของ procs" และ "โหนดในสถานะอิสระ" แต่ฉันต้องการรวมพวกมันเป็นคำสั่งเดียวที่แสดง procs ฟรีทั้งหมด

ในตัวอย่างข้างต้นคำตอบที่ถูกต้องคือ 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' ได้ แต่เฉพาะเมื่อบรรทัดที่อยู่ด้านบนอ่าน 'state = free หรือไม่

คำตอบ:


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

รูปแบบผลลัพธ์ของคุณถูกเตรียมไว้สำหรับ slurp ย่อหน้าของ Perl:

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 }'

บันทึก

สิ่งนี้ใช้งานได้เพราะความคิดของ Perl ของ "ย่อหน้า" เป็นกลุ่มของบรรทัดที่ไม่ว่างคั่นด้วยบรรทัดว่างหนึ่งหรือมากกว่า หากคุณไม่มีบรรทัดว่างระหว่าง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.

ดังนั้นในกรณีของคุณคุณจะต้อง grep state = freeและพิมพ์บรรทัดต่อไปนี้ เมื่อรวมกับตัวอย่างจากคำถามของคุณคุณจะได้สิ่งนั้น:

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: ดูคำตอบของ Stephane
jasonwryan

การsedจับคู่รูปแบบก็เช่นกัน คุณสามารถใช้perlหรือphpหรือภาษาที่คุณต้องการ แต่อย่างน้อยก็พาดหัวของคำถามที่ถามgrep หลายบรรทัด ... ;-)
binfalse

อ๋อ: แต่เมื่อเห็นว่าคุณกำลังใช้อยู่awk... :)
jasonwryan


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.
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.