Как отменить буфер стандартного запуска двоичного файла без 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)"
Другие вопросы по тегам