入力のサイズのみが事前にわかっている場合、パイプ内のコマンドの進行状況をどのように追跡しますか?

入力のサイズのみが事前にわかっている場合、パイプ内のコマンドの進行状況をどのように追跡しますか?

を使用して、遅い操作の進行状況を追跡したいと思いますpv。この操作の入力のサイズは事前にわかっていますが、出力のサイズはわかりません。そのため、pvパイプ内の操作の左側に を配置する必要がありました。

問題は、長時間実行されるコマンドがバッファリングのために入力全体をすぐに消費してしまうことです。これは、パイプ内のバッファリングをオフにする質問ですが、私の場合、遅いのは生成操作ではなく消費操作であり、他の質問に対する回答はどれもこの場合には機能しないようです。

問題を示す簡単な例を以下に示します。

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

進行状況バーは毎秒更新されるのではなく、すぐに 100% にジャンプし、入力の処理にかかる 20 秒間ずっとそこに留まります。pv行が 1 つずつ処理される場合にのみ進行状況を測定できますが、最後のコマンドの入力全体がバッファーに読み込まれるようです。

出力行の数が不明であることを示す、やや長い例:

#! /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

回避策の提案はありますか? ありがとうございます!

答え1

あなたの設定では、データがpv右側で処理されている間に渡されてしまいます。pv次のようにして、右端に移動してみることができます。

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

アップデート: 更新に関しては、おそらく最も簡単な解決策は、名前付きパイプとサブシェルを使用して進行状況を監視することです。

#! /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

関連情報