Можно ли отключить буферизацию для tr?

10

trпохоже, буферизует свои данные, так что эта команда LongRunningCommand|tr \\n ,начнет выводить данные только после накопления нескольких килобайт ввода от LongRunningCommand.

Есть ли способ принудительно trостановить эту буферизацию или любую другую команду, которая может заменить новые строки другим символом без буферизации?


PS Я уже попробовал первые два предложения от Отключить буферизацию в трубе без успеха.

ndemou
источник
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 сама по себе работает нормально. Большое спасибо за предложения, хотя
ndemou
2
Я думаю , что проблема буферизации на самом деле в выходе из tr. Попробуйте|stdbuf -i0 -o0 tr ...
meuh

Ответы:

12

Команды обычно не буферизуют свой ввод. Они сделали бы read()для большого чанка, но при чтении из канала, если в конвейере не так много байтов, read()системный вызов вернет столько символов, сколько есть, и приложение, как правило, будет работать с этим, если сможет ,

Заметным исключением является то, mawkчто будет продолжаться read()до тех пор, пока входной буфер не будет заполнен.

Приложения действительно буферизируют свои выходные данные (stdout). Обычное поведение состоит в том, что если вывод идет в tty, то буферизация будет построчной (то есть, она не начнет записывать в стандартный вывод, пока не получит полную строку для вывода, или заполненную блоком для очень длинная строка), в то время как для любого другого типа файла буферизация выполняется по блокам (то есть запись не начнется, пока не будет заполнен один блок для записи (что-то вроде 4 КБ / 8 КБ ... зависит от программного обеспечения и системы). )).

Таким образом, в вашем случае, 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
Спасибо за подробное объяснение того, что происходит, Стефан.
Высоко
5

Чтобы заменить новые строки на ",", вы можете запустить

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

GNU awk ( gawk) и Solaris nawkбудут работать с буферизацией строки на stdin и без буферизации stdout, когда вывод поступает на терминал. Если ваш awk есть mawk, что происходит в Ubuntu, вы можете дать ему -W interactiveвозможность получить такое же поведение буферизации.

Марк Плотник
источник