Piping várias linhas dentro do script bash

2

Eu tenho alguns logs complicados que tento analisar. O que eu quero é encontrar uma string H , pegar a coluna 5 da linha que combina, e então pegar todas as outras linhas onde a coluna 5 corresponde a linha com a string H .

Exemplo de entrada

a b c d 31 1
a b c d 31 H
a b c d 31 2
a b c d 32 1
a b d d 32 2
a b c d 33 1
a b c d 33 H
a b c d 33 2

Saída esperada

a b c d 31 1
a b c d 31 H
a b c d 31 2
a b c d 33 1
a b c d 33 H
a b c d 33 2

Então, consegui fazer dois scripts separados: script1 | xargs -n1 | script2

script1 procura por string H e imprime a quinta coluna.
cat logfile | grep 'H' | awk '{print $5}'

Em seguida,

script2 imprime todas as outras linhas do arquivo de log, onde a coluna 5 corresponde à saída do primeiro script: cat logfile | awk -v var="$1" '$5 == var'

Eu quero tornar o arquivo de entrada, o arquivo de log, uma variável, para que eu possa usar $ 1 no script e, em seguida, chamar script logfile . Mas então devo mesclar os dois scripts para um script, porque ambos os scripts analisam o mesmo arquivo de log. Qual é, em geral, a abordagem correta para fazer isso? Eu digo geralmente, porque eu sou um novato para bash scripting.

Os dois problemas que eu encouter são, em primeiro lugar: o $ 1 do primeiro script (que é o arquivo de log) é diferente do $ 1 no segundo script (o número que é a saída do primeiro script) que canalizo para awk Em segundo lugar, não consigo encontrar o equivalente a xargs -n1 para uso em um script bash.

    
por Rogier Visser 28.06.2015 / 21:00

1 resposta

2

O segundo awk lê duas entradas, uma após a outra - da saída canalizada do primeiro awk e depois do próprio arquivo. Uma maneira de identificar o início da segunda entrada é que NR (o N umber da entrada atual R ecord, no geral) não corresponde mais a FNR (o número de registro atual de F ile). Observe que - como um argumento FILE arg informa ao awk para obter os dados de stdin (através de um pipe , neste caso).

awk '$6=="H"{print $5}' "$1" |
awk 'NR==FNR{k[$1];next}
     $5 in k{print}' - "$1"

Observe que o método acima de identificar a segunda entrada é de uso comum, mas não se comporta como esperado / desejado quando não há nada para ler da primeira entrada. Para os requisitos deste trabalho, não importa se o primeiro resultado não entregar nada. A lógica nunca passará de NR=FNR , onde construirá uma lista de k valor do índice (ou seja, $1 do arquivo principal) - mas nada é feito com eles - então o script funciona com um valor nulo através do pipe, mas apenas por causa de um efeito colateral desordenado da lógica particular usada.

Existe, no entanto, no GNU awk ( gawk ), uma maneira segura de identificar o arquivo / pipe atual. Há uma variante especial na linha de comando FILE arguments: "... um argumento que tem o formato var = value, atribui valor à variável var - não especifica um arquivo." - veja: Outros Argumentos da Linha de Comando A colocação de tais var = value args é significante - valores necessários para um FILE específico devem ser colocados na linha de comando antes do seu arquivo associado - subseqüente var = value não são aplicados em awk até que os arquivos / canais anteriores tenham sido totalmente lidos.

Aqui está a versão var = value .

gawk '$6=="H"{print $5}' "$1" |
gawk 'fn==1{k[$1];next}
      $5 in k{print}' fn=1 - fn=2 "$1"

saída (é a mesma para as duas versões do script)

a b c d 31 1
a b c d 31 H
a b c d 31 2
a b c d 33 1
a b c d 33 H
a b c d 33 2
    
por 28.06.2015 / 23:27

Tags