Выключите буферизацию в канале

Терминал или консоль являются частью аппаратных средств, с помощью то, который пользователь может взаимодействовать с хостом. В основном клавиатура вместе с текстовым экраном.
В наше время почти все терминалы и консоли представляют "виртуальные".

Файл, который представляет терминал, традиционно, называют tty файлом. Если Вы посмотрите в соответствии с "/dev" каталогом системы UNIX, то Вы найдете много tty файлов подключенным к виртуальным консолям (например, tty1 на Linux), виртуальные терминалы (например, pts/0) или физически подключенные аппаратные средства (например, ttyS0 является физическим последовательным терминалом, если таковые имеются, присоединенный на первом последовательном порте хоста).

Консоль должна быть частью аппаратных средств, физически подключенных с (или часть) хост. Это имеет специальную роль в системе: это - основной момент для доступа к системе для обслуживания, и некоторая специальная операция может быть сделана только от консоли (например, видеть single user mode). Терминал может быть и обычно, удаленная часть аппаратных средств.

Наконец, но не наименьшее, оболочка является специальной программой, которая взаимодействует с пользователем посредством управления tty и предложений, пользователю, способ запустить другие программы (например, удар, csh, tcsh).

Эмулятор терминала является программой, которая эмулирует физический терминал (например, xterm, терминал гнома, minicom).

Таким образом, когда Вы обращаетесь к "текстовому окну", в Вашей системе Linux (под X11) Вы обращаетесь: эмулятор терминала, подключенный к виртуальному терминалу, определенному tty файлом, внутри который выполняет оболочку.

408
27.01.2020, 12:22
13 ответов

Можно использовать unbuffer команда (который стал частью expect пакет), например.

unbuffer long_running_command | print_progress

unbuffer подключения к long_running_command через псевдотерминал (имущество), которое заставляет систему рассматривать его как интерактивный процесс, поэтому не используя буферизацию 4 кибибитов в конвейере, который является вероятной причиной задержки.

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

unbuffer x | unbuffer -p y | z
261
27.01.2020, 19:28
  • 1
    На самом деле использование имущества для соединения с интерактивными процессами верно для, ожидают в целом. –   17.06.2009, 10:58
  • 2
    Чтобы конвейерная обработка вызовов освободила буфер, необходимо использовать-p аргумент так, чтобы освободили буфер чтения от stdin. –   06.10.2009, 23:18
  • 3
    Отметьте: В debian системах это называют expect_unbuffer и находится в expect-dev пакет, не expect пакет –  bdonlan 24.01.2011, 13:14
  • 4
    @bdonlan: По крайней мере, на (находящейся в debian) Ubuntu, expect-dev предоставляет обоим unbuffer и expect_unbuffer (первый - символьная ссылка на последнего). Ссылки доступны с тех пор expect 5.44.1.14-1 (2009). –  jfs 11.04.2013, 16:00
  • 5
    unbuffer в основном expect пакет на debian теперь (это - все еще символьная ссылка на expect_unbuffer, который является также в основном expect пакет) –  cas 05.11.2015, 01:50

Другой способ освежевать эту кошку состоит в том, чтобы использовать stdbuf программа, которая является частью Coreutils GNU (FreeBSD также имеет свой собственный).

stdbuf -i0 -o0 -e0 command

Это выключает буферизацию полностью для входа, вывода и ошибки. Для некоторых приложений буферизация строки может более подойти по причинам производительности:

stdbuf -oL -eL command

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

474
27.01.2020, 19:28
  • 1
    , "освобождают буфер" потребности, которые будут установлены в Ubuntu, которая является в пакете: ожидайте-dev, который составляет 2 МБ... –  lepe 27.06.2013, 09:21
  • 2
    Это работает отлично на установке Raspbian по умолчанию для освобождения буфера, регистрируясь. Я нашел sudo stdbuff … command работы, хотя stdbuff … sudo command не сделал. спасибо –  natevw 10.07.2013, 09:05
  • 3
    @qdii stdbuf не работает с tee, потому что tee перезаписывает значения по умолчанию, установленные stdbuf. См. страницу руководства stdbuf. –  ceving 30.06.2014, 14:51
  • 4
    @lepe Причудливо, освобождают буфер, имеет зависимости от x11 и tcl/tk, означая, что ему на самом деле нужно> 80 МБ при установке его на сервере без них. –  lambshaanxy 28.08.2014, 15:27
  • 5
    @qdii stdbuf использование LD_PRELOAD механизм для вставки его собственной динамично загруженной библиотеки libstdbuf.so. Это означает, что не будет работать с этими исполняемыми файлами видов: с setuid или набором возможностей файла, статически связанным, не использующий стандарт libc. В этих случаях лучше использовать решения с unbuffer / script / socat. См. также stdbuf с setuid/capabilities. –  pabouk 12.10.2015, 12:20

Если это - проблема с libc изменение его буферизации / сбрасывание, когда произведенный не переходит к терминалу, необходимо попробовать socat. Можно создать двунаправленный поток почти между любым видом механизма ввода-вывода. Один из тех является разветвленной программой, говорящей с псевдо tty.

 socat EXEC:long_running_command,pty,ctty STDIO 

То, что это делает,

  • создайте псевдо tty
  • ветвление long_running_command с ведомой стороной имущества как stdin/stdout
  • установите двунаправленный поток между основной стороной имущества и вторым адресом (здесь, это - STDIO),

Если это дает Вам тот же вывод как long_running_command, затем можно продолжить канал.

Редактирование: Ничего себе, не видел освобождать буфер ответ! Ну, socat является большим инструментом так или иначе, таким образом, я мог бы просто оставить этот ответ

52
27.01.2020, 19:28
  • 1
    ... и я не знал о socat - взгляды отчасти как netcat только, возможно, больше.;) Спасибо и +1. –   20.06.2009, 12:32
  • 2
    , который я использовал бы socat -u exec:long_running_command,pty,end-close - здесь –  Stéphane Chazelas 07.08.2015, 16:10

Это раньше имело место и вероятно все еще имеет место, что, когда стандартный вывод записан в терминал, это - строка, буферизованная по умолчанию - когда новая строка записана, строка записана в терминал. Когда стандартный вывод отправляется в канал, он полностью буферизуется - таким образом, данные только отправляются в следующий процесс в конвейере, когда стандартный буфер ввода-вывода заполнен.

Это - источник проблемы. Я не уверен, существует ли очень, можно сделать для фиксации его, не изменяя программу, пишущую в канал. Вы могли использовать setvbuf() функция с _IOLBF отметьте для безусловного помещения stdout в строку буферизовал режим. Но я не вижу простой способ осуществить это на программе. Или программа может сделать fflush() в соответствующих точках (после каждой строки вывода), но тот же комментарий применяется.

Я предполагаю, что при замене канала псевдотерминалом, затем стандартная библиотека I/O думала бы, что вывод был терминалом (потому что это - тип терминала), и выровнял бы буфер автоматически. Это - сложный способ иметь дело с вещами, все же.

11
27.01.2020, 19:28

Я не думаю, что проблема с каналом. Это кажется, что Ваш длительный процесс не сбрасывает свой собственный буфер достаточно часто. Изменение размера буфера канала было бы взломом для обхода его, но я не думаю его возможное, не восстанавливая ядро - что-то, что Вы не хотели бы делать как взлом, поскольку это, вероятно, неохотно влияет на большое количество других процессов.

5
27.01.2020, 19:28
  • 1
    Первопричина состоит в том, что libc переключается на буферизацию 4k, если stdout не является tty. –  Aaron Digulla 16.06.2009, 14:50
  • 2
    Это очень интересно! потому что канал не вызывает буферизации. Они обеспечивают буферизацию, но если Вы читаете из канала, Вы добираетесь, любые данные доступны, Вы не должны ожидать буфера в канале. Таким образом, преступник был бы stdio, буферизующим в приложении. –   16.06.2009, 16:58

Согласно этому размер буфера канала, кажется, установлен в ядре и потребовал бы, чтобы Вы перекомпилировали свое ядро для изменения.

-1
27.01.2020, 19:28
  • 1
    , я верю этому, является различным буфером. –  Samuel Edwin Ward 08.01.2013, 23:58

Для grep, sed и awk можно вынудить вывод быть буферизованной строкой. Можно использовать:

grep --line-buffered

Вывод силы, чтобы быть буферизованной строкой. По умолчанию вывод является строкой, буферизованной, когда стандартный вывод является терминалом и блоком, буферизованным иначе.

sed -u

Сделайте выходную строку буферизованной.

Посмотрите эту страницу для получения дополнительной информации: http://www.perkin.org.uk/posts/how-to-fix-stdio-buffering.html

68
27.01.2020, 19:28

Еще один способ включить буферизующий строку режим вывода для long_running_command должен использовать script управляйте что выполнения Ваш long_running_command в псевдотерминале (имущество).

script -q /dev/null long_running_command | print_progress      # FreeBSD, Mac OS X
script -c "long_running_command" /dev/null | print_progress    # Linux
78
27.01.2020, 19:28
  • 1
    +1 хороший прием, с тех пор script такая старая команда, это должно быть доступно на всех подобных Unix платформах. –  Aaron Digulla 20.01.2013, 15:01
  • 2
    Вам также нужно -q на Linux: script -q -c 'long_running_command' /dev/null | print_progress –  jfs 11.04.2013, 15:51
  • 3
    Это походит на чтения сценария от stdin, который лишает возможности выполнять такой long_running_command в фоновом режиме, по крайней мере, при запуске с интерактивного терминала. К обходному решению я смог перенаправить stdin от /dev/null, начиная с моего long_running_command не использует stdin. –  haridsv 15.11.2013, 14:44
  • 4
    Даже работы над Android. –  not2qubit 03.07.2014, 02:36
  • 5
    Один значительный недостаток: ctrl-z больше не работает (т.е. Я не могу приостановить сценарий). Это может быть зафиксировано, например: отзовитесь эхом | sudo сценарий-c/usr/local/bin/ec2-snapshot-all/dev/null | ts, если Вы не возражаете не быть способными взаимодействовать с программой. ответ –  rlpowell 24.07.2015, 03:03
[1172214] Согласно [1172568] этому посту здесь [1172569], можно попробовать уменьшить трубу ulimit до одного единственного блока размером 512 байт. Это, конечно же, не выключит буферизацию, но хорошо, что 512 байт намного меньше 4K :3[1172215].
2
27.01.2020, 19:28

Вы можете использовать

long_running_command 1>&2 |& print_progress

Проблема в том, что libc будет буферизовать строку при выводе из стандартного потока на экран и в полном буфере при выводе из файла в файл. Но без буфера для stderr.

Я не думаю, что проблема с буфером конвейера, все дело в политике буферов libc.

20
27.01.2020, 19:28

Я знаю, что это старый вопрос, на который уже было много ответов, но если вы хотите избежать проблемы с буфером, просто попробуйте что-нибудь вроде:

stdbuf -oL tail -f /var/log/messages | tee -a /home/your_user_here/logs.txt

Это будет выводить журналы в реальном времени, а также сохранять их в файл logs.txt , и буфер больше не влияет на команду tail -f .

6
27.01.2020, 19:28

Я нашел это умное решение: (echo -e "cmd 1 \ ncmd 2" && cat) | ./shell_executable

Это трюк. cat будет читать дополнительный ввод (до EOF) и передавать его конвейеру после того, как echo поместит свои аргументы во входной поток shell_executable .

1
20.08.2021, 13:40

Подобно ответу chad , вы можете написать небольшой скрипт вроде этого:

# save as ~/bin/scriptee, or so
script -q /dev/null sh -c 'exec cat > /dev/null'

Затем используйте эту команду scriptee вместо tee ].

my-long-running-command | scriptee

Увы, похоже, я не могу заставить такую ​​версию идеально работать в Linux, поэтому, похоже, ограничивается unix-системами в стиле BSD.

В Linux это близко, но вы не получите обратно приглашение, когда оно закончится (пока вы не нажмете Enter и т. Д.) ...

script -q -c 'cat > /proc/self/fd/1' /dev/null
3
20.08.2021, 13:40

Теги

Похожие вопросы