У меня есть скрипт, который вызывает две команды:
long_running_command | print_progress
В long_running_command
печатает прогресс , но я несчастна с ним. Я использую, print_progress
чтобы сделать его более приятным (а именно, я печатаю прогресс в одной строке).
Проблема: подключение канала к stdout также активирует буфер 4K, к хорошей программе печати ничего не получается ... ничего ... ничего ... много ... :)
Как я могу отключить 4K буфер для long_running_command
(нет, у меня нет источника)?
Ответы:
Вы можете использовать
unbuffer
команду (которая входит в составexpect
пакета), например:unbuffer
подключаетсяlong_running_command
через псевдотерминал (pty), что заставляет систему рассматривать его как интерактивный процесс, поэтому не использует буферизацию в 4 КБ в конвейере, которая является вероятной причиной задержки.Для более длинных конвейеров вам, возможно, придется снять буфер каждой команды (кроме последней), например
источник
expect_unbuffer
и находится вexpect-dev
пакете, а не вexpect
пакетеexpect-dev
предоставляет обаunbuffer
иexpect_unbuffer
(первый символическая ссылка на последний). Ссылки доступны сexpect 5.44.1.14-1
(2009).Еще один способ избавиться от этой кошки - использовать
stdbuf
программу, которая является частью GNU Coreutils (FreeBSD также имеет свою собственную).Это полностью отключает буферизацию для ввода, вывода и ошибок. Для некоторых приложений линейная буферизация может быть более подходящей по причинам производительности:
Обратите внимание, что он работает только для
stdio
буферизации (printf()
,fputs()
...) для динамически связанных приложений и только в том случае, если это приложение самостоятельно не регулирует буферизацию своих стандартных потоков, хотя это должно охватывать большинство приложений.источник
sudo stdbuff … command
работы, хотяstdbuff … sudo command
не сделал.stdbuf
не работаетtee
, потому чтоtee
перезаписывает значения по умолчанию, установленныеstdbuf
. Смотрите страницу руководстваstdbuf
.stdbuf
используетLD_PRELOAD
механизм для вставки своей динамически загружаемой библиотекиlibstdbuf.so
. Это означает, что он не будет работать с такими исполняемыми файлами: с установленными возможностями setuid или file, статически связанными, без использования стандартной libc. В этих случаях лучше использовать решения сunbuffer
/script
/socat
. Смотрите также stdbuf с setuid / functions .Еще один способ включить режим вывода с буферизацией строки
long_running_command
- использоватьscript
команду, которая запускает вашlong_running_command
псевдотерминал (pty).источник
script
как это старая команда, она должна быть доступна на всех Unix-подобных платформах.-q
на Linux:script -q -c 'long_running_command' /dev/null | print_progress
stdin
, что делает невозможным запуск такогоlong_running_command
в фоновом режиме, по крайней мере, при запуске из интерактивного терминала. Чтобы обойти это, я смог перенаправить стандартный ввод/dev/null
, так как мойlong_running_command
не используетstdin
.Для
grep
,sed
иawk
вы можете заставить вывод быть буферизованным. Вы можете использовать:Принудительно выводить данные в линейную буферизацию. По умолчанию выход является линейной буферизацией, когда стандартный вывод является терминалом, а блок буферизован иначе.
Сделать строку вывода буферизованной.
Смотрите эту страницу для получения дополнительной информации: http://www.perkin.org.uk/posts/how-to-fix-stdio-buffering.html
источник
Если проблема в том, что libc изменяет свою буферизацию / сброс, когда вывод не идет на терминал, вы должны попробовать socat . Вы можете создать двунаправленный поток между практически любым механизмом ввода / вывода. Одним из них является разветвленная программа, говорящая с псевдотермием.
Что это делает
Если это дает тот же результат, что
long_running_command
и тогда, вы можете продолжить с конвейера.Редактировать: Ух ты не видел небуферный ответ! Ну, в общем, socat - отличный инструмент, так что я мог бы просто оставить этот ответ
источник
socat -u exec:long_running_command,pty,end-close -
здесьВы можете использовать
Проблема в том, что libc будет выполнять линейный буфер при выводе stdout на экран, и полный буфер при выводе stdout в файл. Но нет буфера для stderr.
Я не думаю, что это проблема с буфером буфера, все дело в политике буфера libc.
источник
zsh
(откуда|&
взято адаптировано из csh) иbash
, когда вы это делаетеcmd1 >&2 |& cmd2
, оба fd 1 и 2 подключаются к внешнему стандартному выводу. Таким образом, он работает для предотвращения буферизации, когда этот внешний stdout является терминалом, но только потому, что вывод не проходит через канал (поэтомуprint_progress
ничего не печатает). Так что это тоже самоеlong_running_command & print_progress
(за исключением того, что stdin print_progress - это канал, у которого нет записывающего устройства). Вы можете проверитьls -l /proc/self/fd >&2 |& cat
по сравнению сls -l /proc/self/fd |& cat
.|&
означает сокращение2>&1 |
. Так иcmd1 |& cmd2
естьcmd1 1>&2 2>&1 | cmd2
. Итак, оба fd 1 и 2 в конечном итоге подключены к исходному stderr, и ничего не остается для записи в канал. (s/outer stdout/outer stderr/g
в моем предыдущем комментарии).Раньше так и было, и, вероятно, так и есть, когда стандартный вывод записывается в терминал, он по умолчанию буферизует строку - когда пишется новая строка, строка записывается в терминал. Когда стандартный вывод отправляется в канал, он полностью буферизуется, поэтому данные отправляются следующему процессу в конвейере только после заполнения стандартного буфера ввода / вывода.
Это источник неприятностей. Я не уверен, есть ли что-то, что вы можете сделать, чтобы исправить это, не изменяя запись программы в трубу. Вы можете использовать
setvbuf()
функцию с_IOLBF
флагом, чтобы безоговорочно перевести ееstdout
в режим буферизации строки. Но я не вижу простого способа применить это в программе. Или программа может делатьfflush()
в соответствующих точках (после каждой строки вывода), но тот же комментарий применяется.Я предполагаю, что если вы замените канал псевдотерминалом, то стандартная библиотека ввода / вывода будет думать, что вывод является терминалом (потому что это тип терминала) и будет автоматически выполнять линейный буфер. Хотя это сложный способ иметь дело с вещами.
источник
Я знаю, что это старый вопрос и уже было много ответов, но если вы хотите избежать проблемы с буфером, просто попробуйте что-то вроде:
Это выведет журналы в реальном времени, а также сохранит их в
logs.txt
файл, и буфер больше не будет влиять наtail -f
команду.источник
NOTE: If COMMAND adjusts the buffering of its standard streams ('tee' does for example) then that will override corresponding changes by 'stdbuf'.
Я не думаю, что проблема с трубкой. Похоже, ваш длительный процесс недостаточно часто очищает свой буфер. Изменение размера буфера канала было бы хаком, чтобы обойти его, но я не думаю, что это возможно без перестройки ядра - что-то, что вы не хотели бы делать как хак, так как это, вероятно, затрагивает многие другие процессы.
источник
Согласно этому посту , вы можете попытаться уменьшить ulimit канала до одного 512-байтового блока. Это, конечно, не отключит буферизацию, но хорошо, 512 байт - это меньше, чем 4K: 3
источник
Аналогично ответу Чада , вы можете написать небольшой скрипт, подобный этому:
Затем используйте эту
scriptee
команду в качестве заменыtee
.Увы, я не могу заставить такую версию идеально работать в Linux, поэтому кажется, что она ограничена юниксами в стиле BSD.
В Linux это близко, но вы не получите свое приглашение после его завершения (пока вы не нажмете ввод и т. Д.) ...
источник
script
эмулирует терминал, так что да, я считаю, что он отключает буферизацию. Он также перекликается обратно каждый символ посланного к нему - именно поэтомуcat
отправляются/dev/null
в примере. Что касается работающей внутри программыscript
, то она разговаривает с интерактивным сеансом. Я считаю, что это похоже наexpect
это, но,script
вероятно, является частью вашей базовой системы.tee
, чтобы отправить копию потока в файл. Где указан файлscriptee
?cat
команду наtee myfile.txt
и получить желаемый эффект.Я нашел это умное решение:
(echo -e "cmd 1\ncmd 2" && cat) | ./shell_executable
Это делает трюк.
cat
прочтет дополнительный ввод (до EOF) и передаст его каналу после того,echo
как аргументы вошли в поток вводаshell_executable
.источник
cat
не видит выводecho
; вы просто запускаете две команды в подоболочке, и вывод обеих отправляется в канал. Вторая команда в подоболочке ('cat') читает из родительского / внешнего стандартного ввода, поэтому она работает.В соответствии с этим размер буфера канала, по-видимому, установлен в ядре и потребует от вас перекомпиляции ядра для изменения.
источник