Как отменить буфер стандартного запуска двоичного файла без stdbuf и подобных инструментов
Я хочу отслеживать вывод программы в реальном времени, которую я запускаю. Я пытаюсь сделать это, перенаправив вывод программы в канал, а затем читая канал из сценария мониторинга.
./program >> apipe
тогда из скрипта мониторинга
cat apipe
Однако из-за буфера в >> нет вывода. В любом случае я могу отключить этот буфер? Я работаю во встроенной системе barebone (petalinux), поэтому у меня нет доступа к unbuffer, script или stdbuf, чтобы выручить меня.
Я пробовал скрипты на другой платформе, где доступен небуфер, он работает как я ожидаю.
В любом случае я могу настроить этот буфер или использовать другой двоичный файл для перенаправления?
Редактировать: у меня нет доступа к исходному коду команды, которую я пытаюсь запустить. Это устаревший бинарный файл.
1 ответ
Если у вас нет доступа к stdbuf
Вы можете сымитировать это и снять stdout
вручную с gdb
(при условии, очевидно, у вас есть доступ к gdb
).
Давайте посмотрим, как stdbuf
на самом деле работает. stdbuf
Команда GNU coreutils в основном только внедряет libstdbuf
в пользовательской программе, установив LD_PRELOAD
переменная окружения. (Не имеет значения, но для записи, параметры передаются через _STDBUF_E
/ _STDBUF_I
/ _STDBUF_O
env vars.)
Затем, когда libstdbuf
запускается, это вызывает setvbuf
Функция libc (которая, в свою очередь, выполняет основной системный вызов) для соответствующих файловых дескрипторов (stdin
/ stdout
/ stderr
), в соответствующем режиме (полностью буферизованный, линейный или небуферизованный).
Декларация для setvbuf
в stdio.h
, доступен с man 3 setvbuf
:
#include <stdio.h>
int setvbuf(FILE *stream, char *buf, int mode, size_t size);
Значения для mode
являются: _IONBF
, _IOLBF
, _IOFBF
как определено в stdio.h
, Нас здесь интересует только небуферизованный режим: _IONBF
, Имеет значение 2
(вы можете проверить свой /usr/include/stdio.h
).
Скрипт снятия буфера
Итак, чтобы снять stdout
для какого-то процесса нам просто нужно позвонить:
setvbuf(stdout, NULL, _IONBF, 0)
Мы можем легко сделать это с gdb
, Давайте сделаем сценарий, который мы можем вызвать, unbuffer-stdout.sh
:
#!/bin/bash
# usage: unbuffer-stdout.sh PID
gdb --pid "$1" -ex "call setvbuf(stdout, 0, 2, 0)" --batch
Тогда мы можем назвать это так:
$ ./unbuffer-stdout.sh "$(pgrep -f my-program-name)"
(Вам, вероятно, понадобится sudo
запустить его как root
.)
тестирование
Мы можем использовать эту простую программу на Python с буферизованным стандартным выводом (если не вызывается с -u
и с неустановленным PYTHONUNBUFFERED
), writer.py
:
#!/usr/bin/python
import sys, time
while True:
sys.stdout.write("output")
time.sleep(0.5)
Запустите это с:
$ ./writer.py >/tmp/output &
$ tailf /tmp/output
и наблюдаем, что ничего не появляется, пока мы не запустим
$ sudo ./unbuffer-stdout.sh "$(pgrep -f writer.py)"