Cómo realizar un grep de varias líneas

Cómo realizar un grep de varias líneas

¿Cómo realizarías un grep para un texto que aparece en dos líneas?

Por ejemplo:

pbsnodeses un comando que uso que devuelve la utilización de un clúster de Linux

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

node2
    state = free
    procs = 4
    bar = foobar

node3
    state = busy
    procs = 8
    bar = foobar

Quiero determinar la cantidad de procesos que coinciden con los nodos que están en estado "libre". Hasta ahora he podido determinar el "número de procesos" y "los nodos en estado libre", pero quiero combinarlos en un comando que muestre todos los procesos libres.

En el ejemplo anterior, la respuesta correcta sería 6 (2+4).

Lo que tengo

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

¿Cómo puedo buscar cada línea que dice 'procs = x', pero solo si la línea de arriba dice 'state = free?

Respuesta1

Si los datos siempre están en ese formato, simplemente podrías escribirlos:

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

( RS=mediolos registros son párrafos).

O:

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

Respuesta2

$ 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)

Respuesta3

Esta es una manera de hacerlo usando pcregrep.

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

Ejemplo

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

Respuesta4

Si tiene datos de longitud fija (longitud fija que se refiere al número de líneas en un registro), sedpuede usar el Ncomando (varias veces), que une la siguiente línea al espacio del patrón:

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

debería darte resultados como:

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

Para una composición de registros variable (por ejemplo, con una línea separadora vacía), puede utilizar comandos de bifurcación ty b, pero awkes probable que le lleve allí de una forma más cómoda.

información relacionada