Çok satırlı bir grep nasıl yapılır


15

İki satırda görünen metin için nasıl bir grep yaparsınız?

Örneğin:

pbsnodes linux kümesinin kullanımını döndüren bir komut kullanıyorum

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

node2
    state = free
    procs = 4
    bar = foobar

node3
    state = busy
    procs = 8
    bar = foobar

'Ücretsiz' durumunda olan düğümlerle eşleşen proc sayısını belirlemek istiyorum. Şimdiye kadar "proc'ların sayısını" ve "serbest durumdaki düğümleri" belirleyebildim, ancak bunları tüm ücretsiz proc'ları gösteren tek bir komutta birleştirmek istiyorum.

Yukarıdaki örnekte, doğru cevap 6 (2 + 4) olacaktır.

Neyim var

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' yazan her satırı nasıl arayabilirim, ancak üstündeki satır 'state = free' yazıyorsa?

Yanıtlar:


12

Veriler her zaman bu biçimdeyse, şunu yazabilirsiniz:

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

( RS=Araçlarının kayıt paragrafları ).

Veya:

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

İşte bunu kullanarak yapmanın bir yolu pcregrep.

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

Misal

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

3

Çıktı biçiminiz Perl'in paragraf incelemesi için hazırlanmıştır:

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

Not

Bu yalnızca Perl'in "paragraf" fikri bir veya daha fazla boş satırla ayrılmış boş olmayan satırlar yığını olduğu için çalışır. nodeBölümler arasında boş satırlar olmasaydı, bu işe yaramazdı.

Ayrıca bakınız


3

Sabit uzunluklu bir veriniz varsa (bir kayıttaki satır sayısına atıfta bulunan sabit uzunluk), içinde , desen satırına sonraki satırı birleştiren komutu (birkaç kez) sedkullanabilirsiniz N:

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

size şöyle çıktı vermelidir:

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

Değişken kayıt kompozisyonu için (örneğin boş bir ayırıcı çizgi ile), dallanma komutlarını kullanabilirsiniz tve bancak awksizi oraya daha rahat bir şekilde götürme olasılığı yüksektir.


3

GNU uygulaması grep, satırları bir maçtan önce ( -B) ve sonra ( -A) yazdırmak için iki argümanla birlikte gelir . Kılavuz sayfasından snippet:

   -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.

Yani sizin durumunuzda, state = freeaşağıdaki satırı grep ve yazdırmanız gerekir. Sorunuzdaki parçacıklar ile birleştirdiğinizde şöyle bir şeye ulaşacaksınız:

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

ve biraz daha kısa:

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

awkörüntü eşleştirme yapar; gerek yok grep: Stephane'nin cevabına
jasonwryan

Peki, seddesen eşleştirme de yapıyor. Ayrıca perl, veya phpdilediğiniz dili kullanabilirsiniz. Ama en azından sorunun başlığı çok satırlı grep ... ;-)
binfalse

Evet: ama yine de kullandığını görmek awk... :)
jasonwryan

0

... ve işte bir Perl çözümü:

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

0

awk getlineKomutu kullanabilirsiniz :

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

Gönderen 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.
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.