Como executar um grep multilinha

Como executar um grep multilinha

Como você executaria um grep para texto que aparece em duas linhas?

Por exemplo:

pbsnodesé um comando que utilizo que retorna a utilização de um cluster Linux

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

node2
    state = free
    procs = 4
    bar = foobar

node3
    state = busy
    procs = 8
    bar = foobar

Quero determinar o número de procs que correspondem aos nós que estão no estado 'livre'. Até agora consegui determinar o "número de procs" e "os nós em estado livre", mas quero combiná-los em um comando que mostre todos os procs livres.

No exemplo acima, a resposta correta seria 6 (2+4).

O que eu tenho

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

Como posso procurar cada linha que diz 'procs = x', mas apenas se a linha acima dela diz 'state = free?

Responder1

Se os dados estiverem sempre nesse formato, você poderia simplesmente escrevê-los:

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

( RS=significaregistros são parágrafos).

Ou:

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

Responder2

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

Responder3

Aqui está uma maneira de fazer isso usando pcregrep.

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

Exemplo

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

Responder4

Se você possui dados de comprimento fixo (comprimento fixo referente ao número de linhas em um registro), sedvocê pode usar o Ncomando (várias vezes), que une a próxima linha ao espaço padrão:

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

deve fornecer uma saída como:

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

Para composição de registros variáveis ​​(por exemplo, com uma linha separadora vazia), você pode usar comandos de ramificação te b, mas awké provável que você chegue lá de uma maneira mais confortável.

informação relacionada