Policz liczbę bajtów przesyłanych strumieniowo z jednego procesu do drugiego

17

Używam skryptu powłoki, który przesyła dane z jednego procesu do drugiego

process_a | process_b

Czy ktoś zna sposób, aby dowiedzieć się, ile bajtów zostało przekazanych między tymi dwoma programami? Jedynym rozwiązaniem, jakie mogę teraz wymyślić, byłoby napisanie małego programu c, który odczytuje ze standardowego wejścia, zapisuje na standardowe wyjście i zlicza wszystkie przesłane dane, przechowując liczbę w zmiennej środowiskowej, takiej jak:

process_a | count_bytes | process_b

Czy ktoś ma lepsze rozwiązanie?

Simon Hodgson
źródło

Odpowiedzi:

16

Rurociąg przez dd. Domyślnym wejściem dd jest stdin, a domyślnym wyjściem jest stdout; kiedy zakończy stdin / stdout I / O, zgłosi stderr, ile danych przesłał.

Jeśli chcesz przechwycić wyjście dd, a inne programy już rozmawiają ze stderr, użyj innego deskryptora pliku. Na przykład,

$ exec 4>~/fred
$ input-command | dd 2>&4 | output-command
$ exec 4>&-
Phil P.
źródło
2
Nie możesz pominąć execi bezpośrednio wyprowadzić do pliku? input-command | dd 2>~/fred | output-command
Wstrzymano do odwołania.
2
Tak. Przepraszam, najwidoczniej miałem jedną z tych „chwil”.
Phil P
28

Użyj pv przeglądarki rur. To świetne narzędzie. Gdy się o tym dowiesz, nigdy nie dowiesz się, jak bez niego żyłeś.

Może także pokazywać pasek postępu i „szybkość” przesyłania.

Rory
źródło
Podczas poszukiwań natknąłem się na to, ale potrzebuję go, aby ustawić zmienną z liczbą przesłanych bajtów, aby móc użyć jej w innym procesie.
Simon Hodgson,
Przykład użycia: cat file | pv -bzwróci rozmiar pliku.
rodorgas
6

process_a | tee >(process_b) | wc --bytespowinno działać. Następnie możesz przekierować wclicznik tam, gdzie jest to potrzebne. Jeśli process_bwypisujesz coś do stdout/ stderrprawdopodobnie prawdopodobnie będziesz musiał to gdzieś przekierować /dev/null.

Dla nieco wymyślonego przykładu:

filestore:~# cat document.odt | tee >(dd of=/dev/null 2>/dev/null) | wc --bytes
4295

Dla wyjaśnienia: teepozwala >()przekierować dane wyjściowe do wielu plików (plus standardowe wyjście), a konstrukcja jest „podstawieniem procesu” bash, co sprawia, że ​​proces wygląda jak plik tylko do zapisu, dzięki czemu można przekierowywać zarówno do procesów, jak i plików ( zobacz tutaj lub to pytanie + odpowiedź, aby zobaczyć przykład użycia teewysyłania danych wyjściowych do wielu procesów).

David Spillett
źródło
Podoba mi się to rozwiązanie, niestety wydaje się, że używany przeze mnie skrypt (BusyBox) nie obsługuje notacji> (), ale zapewnia sposób robienia tego, o co mi chodzi.
Simon Hodgson,
Tak, potrzebujesz dość kompletnego basha, aby mieć tę funkcję - jest to coś, co nie jest powszechnie używane, więc usuwa się go z przyciętych pocisków (nawet tych, których celem jest zgodność mniej lub bardziej bash) jak zajęty, aby zaoszczędzić miejsce.
David Spillett,
1

Wiem, że jestem spóźniony na imprezę, ale wierzę, że mam dobrą odpowiedź, która może poprawić ten przydatny wątek.
Jest to połączenie odpowiedzi @Phil P i @Didid Spillett, ale:

  • inaczej niż @Phil P, unika tworzenia nowego pliku
  • inaczej niż w @David Spillett, utrzymuje strukturę potoku

Liczba bajtów jest wypisywana na standardowe wyjście, wraz z dowolnym wyjściem procesu_b.
Przedrostka można użyć do identyfikacji wiersza zawierającego bajty podczas pracy z danymi wyjściowymi ( Bytes:w przykładzie).

exec 3>&1
process_a | tee >({ echo -n 'Bytes:'; wc -c; } >&3) | process_b
exec 3>&-

OSTRZEŻENIE:
Nie należy polegać na kolejności wierszy na wyjściu
. Kolejność jest nieprzewidywalna i zawsze może się różnić, nawet podczas wywoływania tego samego skryptu z tymi samymi parametrami!

Claudio
źródło
Niestety, wciąż jest to konstrukcja typu bash ...
Mikhail T.