Czy mogę wyłączyć buforowanie dla tr

10

trwydaje się buforować dane wejściowe, dzięki czemu to polecenie LongRunningCommand|tr \\n ,zacznie generować dane wyjściowe dopiero po zgromadzeniu kilku kilobajtów danych wejściowych z LongRunningCommand.

Czy istnieje sposób na wymuszenie trzatrzymania buforowania lub innego polecenia, które może zastąpić nowe wiersze innym znakiem bez buforowania?


PS Próbowałem już dwóch pierwszych sugestii z Wyłącz buforowanie w potoku bez powodzenia.

ndemou
źródło
1
czy zastosowałeś się stdbufdo LongRunningCommand lub do tr, czy do obu, inaczej?
Meuh
Obaj lubią to:stdbuf -o0 fping -aAq -r2 -g 10.30.0.1 10.30.0.255 2>/dev/null | stdbuf -i0 tr \\n ,
ndemou
fping -qmówi „Nie pokazuj wyników dla pojedynczej sondy, ale tylko końcowe podsumowanie”, więc może to tylko jeden długi napis na końcu?
Meuh
Żadne polecenie fping nie działa samo z siebie dobrze. Bardzo dziękuję za sugestie
2015
2
Myślę, że problem jest w rzeczywistości buforowania w wyjściu z tr. Spróbuj|stdbuf -i0 -o0 tr ...
meuh

Odpowiedzi:

12

Polecenia na ogół nie buforują danych wejściowych. Zrobiliby to read()dla dużej porcji, ale jeśli czytając z potoku, nie ma tak wielu bajtów w potoku, read()wywołanie systemowe powróci z tyloma znakami, a aplikacja na ogół będzie z tym pracować, jeśli może .

Godnym uwagi wyjątkiem jest to, mawkktóre będzie się utrzymywało read()do momentu zapełnienia bufora wejściowego.

Aplikacje buforują jednak dane wyjściowe (standardowe wyjście). Zwykle zachowuje się tak, że jeśli dane wyjściowe zmienią się na tty, wówczas buforowanie będzie przebiegać liniowo (to znaczy, że nie zacznie zapisywać do standardowego wyjścia, dopóki nie będzie miał pełnej linii do wyjścia lub pełnego bloku dla bardzo długa linia), podczas gdy dla każdego innego typu pliku buforowanie odbywa się według bloków (to znaczy, że nie zacznie pisać, dopóki nie zostanie zapełniony jeden blok (coś takiego jak 4KiB / 8KiB ... zależy od oprogramowania i systemu) )).

Więc w twoim przypadku LongRunningCommandprawdopodobnie buforuje swoje wyjście blokami (ponieważ jego wyjściem jest potok, a nie tty), i trprawdopodobnie buforuje jego wyjście według linii, ponieważ prawdopodobnie jest to terminal.

Ponieważ jednak usuniesz każdy znak nowej linii z jego wyniku, nigdy nie wypisze on wiersza, więc buforowanie będzie odbywało się według bloku.

Więc tutaj chcesz wyłączyć buforowanie dla obu LongRunningCommandi tr. W systemach GNU lub FreeBSD:

stdbuf -o0 LongRunningCommand | stdbuf -o0 tr '\n' ,

Pamiętaj, że jeśli chcesz połączyć linie przecinkiem, lepszym rozwiązaniem jest użycie paste -sd , -. W ten sposób wyjście zostanie zakończone znakiem nowej linii (prawdopodobnie nadal będziesz musiał wyłączyć buforowanie).

Stéphane Chazelas
źródło
@mikeserv. Tak, i taki, który używa buforowania stdio i nie wywołuje samego setvbuf / setbuffer ... i nie jest wbudowany w powłokę. Ale ogólnie w systemach GNU i FreeBSD wszystkie te warunki są spełnione.
Stéphane Chazelas
O. Dowiedziałem się o tym dopiero kilka dni temu, kiedy byłem rozczarowany, że nie mogłem wpływać na strumienie we / wy dla mojego statycznie skompilowanego sed. przepraszam, jeśli to było denerwujące - ale nie zdawałem sobie sprawy, że to wiedza ogólna. Myślę, że używa LD_PRELOAD.
mikeserv
Dzięki za dokładne wyjaśnienie, co się dzieje Stéphane. Bardzo mile widziane
ndemou
5

Aby zastąpić znaki nowej linii ",", możesz uruchomić

awk '{ printf "%s,", $0 }'

GNU awk ( gawk) i Solaris nawkbędą działać z buforowaniem linii na stdin i bez buforowania stdout, gdy wyjście jest na terminalu. Jeśli masz awk mawk, co dzieje się na Ubuntu, możesz dać mu -W interactiveopcję uzyskania takiego samego zachowania buforowania.

Mark Plotnick
źródło