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
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), sed
você pode usar o N
comando (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 t
e b
, mas awk
é provável que você chegue lá de uma maneira mais confortável.