Como acompanhar o progresso de um comando em um pipe se apenas o tamanho de sua entrada for conhecido antecipadamente?

5

Gostaria de acompanhar o progresso de uma operação lenta usando pv . O tamanho da entrada desta operação é conhecido antecipadamente, mas o tamanho de sua saída não é. Isso me forçou a colocar pv à esquerda da operação no pipe.

O problema é que o comando de longa duração imediatamente consome toda a sua entrada por causa do buffer. Isso é um pouco semelhante ao Desativar o buffer no pipe pergunta, mas no meu caso é a operação de consumo que é lenta, não a produção e nenhuma das respostas à outra pergunta parece funcionar neste caso.

Aqui está um exemplo simples demonstrando o problema:

seq 20 | pv -l -s 20 | while read line; do sleep 1; done
  20 0:00:00 [13.8k/s] [=====================================>] 100%

Em vez de ser atualizada a cada segundo, a barra de progresso pula imediatamente para 100% e permanece lá durante os 20 segundos necessários para processar a entrada. pv só poderia medir o progresso se as linhas fossem processadas uma por uma, mas a entrada inteira do último comando parece ser lida em um buffer.

Um exemplo um pouco mais longo que também demonstra o número desconhecido de linhas de saída:

#! /bin/bash
limit=10
seq 20 | \
  pv -l -s 20 | \
  while read num
do
  sleep 1
  if [ $num -gt $limit ]
  then
    echo $num
  fi
done

Alguma sugestão para uma solução alternativa? Obrigado!

    
por Zoltan 22.10.2016 / 18:28

1 resposta

6

Na sua configuração, os dados passaram pv enquanto ainda são processados no lado direito. Você poderia tentar mover pv para o lado mais à direita desta forma:

seq 20 | while read line; do sleep 1; echo ${line}; done | pv -l -s 20 > /dev/null

Atualização: Com relação à sua atualização, talvez a solução mais fácil seja usar um pipe nomeado e um subshell para monitorar o progresso:

#! /bin/bash
trap "trap - SIGTERM && kill -- -$$" SIGINT SIGTERM EXIT
(rm /tmp/progress.pipe; mkfifo /tmp/progress.pipe; tail -f /tmp/progress.pipe | pv -l -s 20 > /dev/null)&
limit=10
seq 20 | \
  while read num
do
  sleep 1
  if [ $num -gt $limit ]
  then
    echo $num
  fi
  echo $num > /tmp/progress.pipe
done
    
por 22.10.2016 / 18:51

Tags