Почему stdbuf не влияет на Python? - PullRequest
3 голосов
/ 12 апреля 2019

Учитывая следующую программу на Python:

import sys

print("input")
while True:
    pass

и эквивалент в C:

#include <stdio.h>

int main() {
        printf("input\n");
        while(1);
        return 0;
}

Когда я передаю программу с cat, вывод по умолчанию буферизуется (вместо буферизации строки). Как следствие, у меня нет вывода:

% python3 ./a.py | cat
(empty)

% ./a.out | cat
(empty)

Я могу использовать stdbuf, чтобы вернуться к буферизации строк:

% stdbuf -oL ./a.out | cat
input

Но это не работает с Python:

% stdbuf -oL python3 a.py | cat
(empty)

Есть идеи, почему? Я знаю о существовании python3 -u, но я хочу буферизацию строки, а не "без буферизации", и я хочу, чтобы эта командная строка работала и для других языков. Команда unbuffer, кажется, тоже работает, но я хотел бы понять, почему stdbuf здесь не работает.

Ответы [ 2 ]

2 голосов
/ 12 апреля 2019

По умолчанию функция Python print() направляет свой вывод в sys.stdout, в документации которого указано это:

В интерактивном режиме потоки stdout и stderr имеют линейную буферизацию. В противном случае они буферизируются как обычные текстовые файлы. Вы можете переопределите это значение с помощью параметра командной строки -u.

Обратите внимание, что эти документы не оставляют места для общих влияний окружающей среды, таких как команда stdbuf, в режиме буферизации sys.stdout: он не буферизуется, если использовалась опция -u (или, эквивалентно, если установлена ​​переменная окружения PYTHONUNBUFFERED), в противном случае буферизация строки, если она интерактивная, и буферизация блока, если она не интерактивная.

Программы могут управлять своей собственной буферизацией, поскольку документы stdbuf подтверждают:

ПРИМЕЧАНИЕ. Если COMMAND настраивает буферизацию своих стандартных потоков ('tee') делает, например,) тогда это переопределит соответствующие настройки, измененные по 'stdbuf'. Также некоторые фильтры (например, «dd», «cat» и т. Д.) Не используют потоки для ввода / вывода, и, следовательно, не зависят от настроек 'stdbuf'.

Поскольку Python явно указывает детали буферизации, разумно ожидать, что он фактически утвердительно управляет своей буферизацией, таким образом подавляя любой эффект stdbuf.

0 голосов
/ 12 апреля 2019

Похоже, python решает, использовать ли буферизацию или нет, основываясь на isatty.

Я использовал этот сценарий (из обманывает приложение, полагая, что его стандартный вывод - это терминал, а неpipe ):

faketty() {
    script -qfc "$(printf "%q " "$@")" /dev/null
}

И это работает:

% faketty python3 a.py | cat
input

(И это с буферизацией строки)

...