
Ich möchte den Fortschritt einer langsamen Operation mithilfe von verfolgen pv
. Die Größe der Eingabe dieser Operation ist im Voraus bekannt, die Größe der Ausgabe jedoch nicht. Dies zwang mich dazu, pv
links von der Operation in der Pipe zu platzieren.
Das Problem ist, dass der lang laufende Befehl aufgrund der Pufferung sofort seine gesamte Eingabe verbraucht. Dies ähnelt demPufferung in der Pipe deaktivierenFrage, aber in meinem Fall ist der konsumierende Vorgang langsam, nicht der produzierende, und keine der Antworten auf die andere Frage scheint in diesem Fall zu funktionieren.
Hier ist ein einfaches Beispiel, das das Problem veranschaulicht:
seq 20 | pv -l -s 20 | while read line; do sleep 1; done
20 0:00:00 [13.8k/s] [=====================================>] 100%
Anstatt jede Sekunde aktualisiert zu werden, springt der Fortschrittsbalken sofort auf 100 % und bleibt dort für die gesamten 20 Sekunden, die die Verarbeitung der Eingabe dauert. pv
könnte den Fortschritt nur messen, wenn die Zeilen einzeln verarbeitet würden, aber die gesamte Eingabe des letzten Befehls scheint in einen Puffer gelesen zu werden.
Ein etwas längeres Beispiel, das auch die unbekannte Anzahl der Ausgabezeilen demonstriert:
#! /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
Irgendwelche Vorschläge für eine Problemumgehung? Danke!
Antwort1
In Ihrem Setup sind die Daten durchgegangen, pv
während sie auf der rechten Seite noch verarbeitet wurden. Sie könnten versuchen, pv
wie folgt ganz nach rechts zu gelangen:
seq 20 | while read line; do sleep 1; echo ${line}; done | pv -l -s 20 > /dev/null
Aktualisieren: In Bezug auf Ihr Update besteht die einfachste Lösung möglicherweise darin, eine benannte Pipe und eine Subshell zu verwenden, um den Fortschritt zu überwachen:
#! /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