Policz liczbę wierszy wyjścia z poprzedniego programu

32

Próbuję policzyć liczbę wierszy danych wyjściowych, które wytwarza dany program. Problem polega na tym, że uruchomienie programu zajmuje dużo czasu i chcę wyświetlić dane wyjściowe użytkownikowi. Czy istnieje sposób na policzenie liczby wierszy wypisanych przez ostatnie polecenie?

Mógłbym to zrobić, program | wc -lale to nie pokazałoby wyjścia użytkownikowi. O ile wiem, muszę to zrobić program; program | wc -l- ale uruchomienie programu zajmuje co najmniej minutę, więc nie chcę tego robić więcej niż jeden raz, aby wyświetlić liczbę wierszy na dole.

EDYTOWAĆ:

  • Czy istnieje sposób na pokazanie wyniku w postaci, w jakiej się on odbywa (linia po linii), a następnie zwrócenie liczby na końcu?
Libbux
źródło
A może: niech program śledzi swoje dane wyjściowe i po prostu odczytuje tę wartość ze zmiennej (np. STDOUT_WRITE_COUNT) Lub rejestruje ją w pliku / interfejsie API na końcu programu. WDYT?
mecampbellsoup

Odpowiedzi:

43

Możesz użyć teedo podzielenia strumienia wyjściowego, wysyłając jedną kopię do, wca drugą kopię do STDOUT jak zwykle.

program | tee >(wc -l)

Jest >(cmd)to składnia bash, która oznacza uruchomienie cmdi zastąpienie >(cmd)bitu ścieżką do (nazwanego potoku podłączonego) STDIN tego programu.

Patrick
źródło
2
>(cmd)jest kshrównież składnia rozpoznawana przez zshi bashużywa nazwanych potoków w systemach, które nie mają /dev/fd/n.
Stéphane Chazelas
@StephaneChazelas Tak, większość powłok obsługuje go, ale nie ma go w POSIX, więc nie można polegać na tym, że jest wszędzie.
Patrick,
Tak, właśnie wskazałem, że podstawienie procesu nie jest bashwynalazkiem, ponieważ sformułowanie w twojej odpowiedzi mogło pozwolić uwierzyć.
Stéphane Chazelas
1
@TheLibbster Zależy jak zdefiniować efektywne. Ta metoda wymaga odrodzenia 2 dodatkowych procesów, gdzie as sedi awksą tylko jednym. Ale teei wcoba są bardzo małe (znacznie mniejsze niż sedi awk).
Patrick
1
@ TheLibbster tak, zgodnie z kilkoma prostymi testami, które właśnie wykonałem, jest to około dwa razy szybsze niż metody sedi awk. ( ddDodałem 100mb /dev/urandomdo pliku, a następnie kilkakrotnie uruchomiłem ten plik za pomocą każdej metody)
Patrick
10

Jedną z opcji jest użycie awk, który może wykonać liczenie i wydrukować na standardowe wyjście.

program | awk '{ print } END { print NR }'

W awk, NR to bieżący numer linii. Możesz to zrobić za pomocą perla:

program | perl -pe 'END {print "$.\n"}'

Lub sed:

program | sed -n 'p;$='
Jordan
źródło
Czy istnieje sposób na pokazanie wyniku w postaci, w jakiej się on odbywa (linia po linii), a następnie zwrócenie liczby na końcu?
Libbux 17.04.13
6

Możesz sklonować stdout na stderr.

program | tee /dev/stderr | wc -l

W ten sposób programwyjście standardowe jest teezapisywane na stderr, który jest wydrukowany na konsoli. teezapisuje także dane przesyłane do niego na standardowe wyjście, do którego jest przesyłane wc.


źródło
3

moja ulubiona opcja:

program | grep "" -c
Montells
źródło
1
OP mógł zapytać o coś innego, ale przyszedłem tutaj, szukając tylko liczby wyjściowych wierszy i nie przejmowałem się wyświetlaniem rzeczywistej wydajności, i to działa. Dzięki!
Nikhil VJ
0
tail -f /var/log/squid/access.log | ( c=0; pl() { echo $c; c=0; }; trap pl SIGHUP; while read a; do (( c=c+1 )); done ) & ( trap 'kill $! ; exit' SIGINT; trap '' SIGHUP; while true; do kill -HUP $! ; sleep 1; done)
złoty
źródło
0

To może być późno. Chciałbym jednak odpowiedzieć na twoje pytanie uzupełniające, jak złapać zliczoną liczbę w zmiennej.

To jest to czego chcesz YOUR_VAR=$(PROGRAM | tee /dev/stderr | wc -l).

Korzystamy z teegenerowania tutaj dwóch strumieni i kierujemy jeden do /dev/stderr, który pojawi się na ekranie, a drugi do wc -l, który zgłosi liczbę linii.

Huangzonghao
źródło