Чи можу я відключити буферизацію для tr


10

trЗдається, буферний вхід таким чином, що ця команда LongRunningCommand|tr \\n ,почне виробляти вихід лише після накопичення кількох кілобайт входу від LongRunningCommand.

Чи є спосіб змусити trзупинити цю буферизацію чи будь-яку іншу команду, яка може замінити нові рядки на інші символи без буферизації?


PS Я вже без успіху спробував перші дві пропозиції з Вимкнути буферизацію в трубі .


1
ви зверталися stdbufдо LongRunningCommand або до tr, або до обох, по-різному?
meuh

Для обох, як це:stdbuf -o0 fping -aAq -r2 -g 10.30.0.1 10.30.0.255 2>/dev/null | stdbuf -i0 tr \\n ,
ndemou

fping -qкаже: "Не показуйте результати за зондом, а лише підсумковий підсумок", тож, можливо, це лише один довгий запис у кінці?
meuh

Жодна команда fping не працює чудово сама по собі.
Дуже

2
Я думаю , що проблема буферизації насправді в виході з tr. Спробуйте|stdbuf -i0 -o0 tr ...
meuh

Відповіді:


12

Команди, як правило, не буферують свій вхід. Вони зробили б read()великий фрагмент, але якщо читати з труби, якщо в трубі не так багато байтів, read()системний виклик повернеться з такою кількістю символів, і програма, як правило, працює з цим, якщо зможе .

Помітним винятком є ​​те, mawkщо буде тривати read()до тих пір, поки вхідний буфер не заповниться.

Хоча програми буферують свій вихід (stdout). Звичайна поведінка полягає в тому, що якщо вихід збирається в tty, то буферизація буде лінійною (тобто вона не почне писати до stdout, поки у неї не буде повна лінія для виведення, або блок-full для дуже довгий рядок), а для кожного іншого типу файлів буферизація здійснюється блоками (тобто він не почне писати, доки не буде заповнений один блок для запису (щось на зразок 4KiB / 8KiB ... залежить від програмного забезпечення та системи )).

Тож у вашому випадку LongRunningCommandймовірно буферизує його вихід блоками (оскільки його вихід - це труба, а не tty), і, trймовірно, буферизує його вихід за рядком, оскільки його вихід, ймовірно, є терміналом.

Але, оскільки ви видаляєте кожен символ нового рядка зі свого виводу, він ніколи не виводить лінію, тому буферизація буде здійснюватися блоком.

Отже, тут ви хочете відключити буферизацію і для, LongRunningCommandі для tr. У системах GNU або FreeBSD:

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

Зауважте, що якщо ви хочете з'єднати рядки комою, кращим підходом є використання paste -sd , -. Таким чином вихід буде припинено символом нового рядка (вам, ймовірно, все одно потрібно буде відключити буферизацію).


@mikeserv. Так, і той, який використовує буферизацію stdio і не викликає setvbuf / setbuffer ... сам по собі і не є вбудованою оболонкою. Але загалом у системах GNU та FreeBSD всі ці умови виконуються.
Стефан Шазелас

ой. Я дізнався, що сам кілька днів тому, коли розчарувався, що не можу вплинути на потоки вводу / виводу для моїх статично складених sed. Вибачте, якщо це дратувало - але я не зрозумів, що це загальне знання. я думаю, він використовує LD_PRELOAD.
mikeserv

Дякуємо за ретельне пояснення того, що відбувається Стефане. Дуже вдячний
ndemou

5

Щоб замінити нові рядки на ",", можна запустити

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

GNU awk ( gawk) і Solaris nawkзапускаються з буферизацією рядків на stdin та без буферизації stdout, коли вихід на термінал. Якщо ваш awk є mawk, що відбувається на Ubuntu, ви можете дати йому -W interactiveможливість отримати таку саму буферну поведінку.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.