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

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

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

O problema é que o comando de longa execução consome imediatamente toda a sua entrada devido ao buffer. Isto é um pouco semelhante aoDesative o buffer no pipepergunta, mas no meu caso é a operação de consumo que é lenta, não a de produção e nenhuma das respostas para a outra pergunta parece funcionar neste caso.

Aqui está um exemplo simples que demonstra 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 salta imediatamente para 100% e permanece lá durante os 20 segundos necessários para processar a entrada. pvsó poderia medir o progresso se as linhas fossem processadas uma por uma, mas toda a entrada 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!

Responder1

Na sua configuração, os dados passaram pvenquanto ainda são processados ​​no lado direito. Você poderia tentar mover pvpara o lado direito assim:

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

Atualizar: Em 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

informação relacionada