Trunca a saída após X linhas e imprime a mensagem se e somente se a saída foi truncada

6

Digamos que eu precise apenas das 5 primeiras linhas de uma saída para fins de registro. Eu também preciso saber se e quando o log foi truncado.

Estou tentando usar head para fazer o trabalho, o comando seq abaixo exibe 20 linhas que são truncadas por head e eu echo uma informação truncada:

 > seq -f 'log line %.0f' 20 | head -n 5 && echo '...Output truncated. Only showing first 5 lines...'
log line 1
log line 2
log line 3
log line 4
log line 5
...Output truncated. Only showing first 5 lines...

Mas se o comando seq gerar menos de 5 linhas, usando a mesma construção acima, recebo um status "truncado" incorreto:

seq -f ' log line %.0f' 3 | head -n 5 && echo '...Output truncated. Only showing first 5 lines...'
log line 1
log line 2
log line 3
...Output truncated. Only showing first 5 lines...

Existe uma maneira de o comando head (ou outra ferramenta) me informar se truncou alguma coisa para que eu exiba apenas a mensagem "... truncado ..." quando necessário?

    
por Gohu 21.03.2018 / 15:25

2 respostas

12

Uma nota de aviso:

Quando você faz:

cmd | head

e se a saída for truncada, isso pode fazer com que cmd seja eliminado por um SIGPIPE, se ele gravar mais linhas depois que head tiver saído. Se não for o que você deseja, se você quiser que cmd continue sendo executado depois, mesmo que sua saída seja descartada, será necessário ler, mas descartar as linhas restantes em vez de sair após 10 linhas terem sido impressas (por exemplo, com sed '1,10!d' ou awk 'NR<=10' em vez de head ).

Então, para as duas abordagens diferentes:

saída truncada, cmd pode ser eliminada

cmd | awk 'NR>5 {print "TRUNCATED"; exit}; {print}'
cmd | sed  '6{s/.*/TRUNCATED/;q;}'

Observe que a implementação mawk de awk acumula um buffer cheio de entrada antes de começar a processá-lo, portanto cmd pode não ser eliminado até ter escrito um buffer cheio (8KiB no meu sistema AFAICT) dados. Isso pode ser contornado usando a opção -Winteractive .

Algumas implementações de sed também leem uma linha de antecedência (para saber qual é a última linha ao usar o endereço $ ), portanto, com essas, cmd só pode ser eliminado depois de ter saído Linha 7 th .

saída truncada, o restante descartado para que cmd não seja eliminado

cmd | awk 'NR<=5; NR==6{print "TRUNCATED"}'
cmd | sed '1,6!d;6s/.*/TRUNCATED/'
    
por 21.03.2018 / 15:49
6

Você pode usar o AWK:

seq -f 'line %.0f' 20 | awk 'NR <= 5; NR > 5 { print "...Output truncated. Only showing first 5 lines..."; exit }'

Isto imprime as primeiras cinco linhas (se houver) como estão; se ele vir uma linha além disso, ele emitirá a mensagem de truncamento e sairá.

Você pode especificar o código de saída a ser usado se quiser implementar o processamento condicional:

seq -f 'line %.0f' 20 | awk 'NR <= 5; NR > 5 { exit 1 }' || echo ...Output truncated. Only showing first 5 lines...
    
por 21.03.2018 / 15:27