Trójnik nie pobiera całej mocy z rury

12

Mam skrypt wykonujący polecenia takie jak:

export LD_LIBRARY_PATH=.:$LD_LIBRARY_PATH;./some_app -i $INDEX | tee $LOG
echo "Number of errors: $(grep "ERROR" $LOG | wc -l)"

Problem jest prawdopodobnie w potoku do tee . Nie wydaje się, aby uzyskać całą moc wyjściową. Gdy aplikacja kończy pracę, brakuje kilku ostatnich wierszy danych wyjściowych (zwykle tych zawierających błąd krytyczny). Kiedy uruchamiam aplikację bez potoku tee, otrzymuję je na wyjściu.

Jak zmusić skrypt do czekania, aż tee zakończy przetwarzanie wszystkich danych wyjściowych?

Ladislav Mrnka
źródło
Czy działa OK, jeśli umieścisz go w pliku, a nie w standardowym pliku?
Pilot6

Odpowiedzi:

23

Błąd krytyczny prawdopodobnie pojawia się w STDERR (2), a nie w STDOUT (1). Możesz przekierować STDERR do STDOUT za pomocą, 2>&1a następnie potok powinien go również przechwycić.

./some_app -i $INDEX 2>&1 | tee $LOG

Jeśli masz problemy z buforowaniem u góry, możesz zmusić go do stanu niebuforowanego:

stdbuf -o0 ./some_app -i $INDEX 2>&1 | tee $LOG
Oli
źródło
Dobrze, zbliżamy się. Teraz widzę, że błąd krytyczny jest drukowany, ale znowu nie jest kompletny. Linia z błędem kończy się na środku, a echo jest kontynuowane. Nadal występuje problem z opróżnianiem bufora lub po prostu czekaniem na ukończenie tej części.
Ladislav Mrnka
Edytowane. Dość rzadko z mojego doświadczenia, że ​​coś tak całkowicie prześlizguje się przez bufory przy wyjściu, ale warto spróbować.
Oli
1
Gotowy! Dziękuję Ci. Mogę zadawać zbyt wiele pytań, ale czy ktoś rozumie, dlaczego muszę wyłączyć buforowanie podczas przesyłania do innego procesu?
Ladislav Mrnka
@Oli Bardzo dobry!
Pilot6
6

Ponieważ komunikaty o błędach są zwykle wyświetlane w STDERR (deskryptor pliku 2), musisz przekierować zarówno STDOUT, jak i STDERR, aby tee:

./some_app -i "$INDEX" |& tee "$LOG"

Gdy to zrobisz ./some_app -i $INDEX | tee $LOG, przekierowujesz tylko STDOUT do tee.

|& spowoduje przekierowanie STDOUT i STDERR.

Jeśli nie możesz przekierować tylko STDOUT (tak jak byłeś):

./some_app -i "$INDEX" | tee "$LOG"

Z drugiej strony, jeśli chcesz przekierować tylko STDERR:

./some_app -i "$INDEX" 2>&1 >/dev/null | tee "$LOG"
heemayl
źródło