Wie lässt sich der Fortschritt eines Befehls in einer Pipe verfolgen, wenn nur die Größe der Eingabe im Voraus bekannt ist?

Wie lässt sich der Fortschritt eines Befehls in einer Pipe verfolgen, wenn nur die Größe der Eingabe im Voraus bekannt ist?

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, pvlinks 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. pvkö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, pvwährend sie auf der rechten Seite noch verarbeitet wurden. Sie könnten versuchen, pvwie 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

verwandte Informationen