Получение stdin из именованного канала

10

То, что я пытаюсь сделать, это запустить python в окне терминала и перенаправить его stdin из именованного канала. Затем я пишу в именованный канал в другом терминале и выполняю эту команду на python.

Терминал 1:

mkfifo p1
python < p1

Терминал 2:

echo -n "print \"Hello World\"" > p1

Что происходит, - Python печатает Hello Worldи выходит. Я хочу, чтобы Python работал и выполнял следующую команду. Как мне это сделать в оболочке?

Лорд лох
источник

Ответы:

10

Тебе нужно

  • Запустите python в интерактивном режиме, даже если его стандартный ввод не является терминалом: используйте python -i
  • оставьте открытый конец канала открытым, иначе python обнаружит EOF и завершит работу.

Так:

python -i < p1

И в других местах:

exec 3> p1
echo '1j*1j' >&3
...
# and when done, close that file descriptor so python sees the EOF:
exec 3>&-
Стефан Шазелас
источник
Спасибо! Это сработало. Я не знаком с тем, что вы сделали. Не могли бы вы добавить некоторые детали в свой ответ, чтобы объяснить, что происходит. Что exec 3> p1делает и что такое &3& exec 3> &1? Спасибо.
Лорд Ло.
1
Ваш ответ напомнил мне об этом баннере - sphotos-b.xx.fbcdn.net/hphotos-ash4/… это обложка фотографии друга на фейсбуке :-)
Лорд Лох.
Вопрос, будет exec 3>&-работать так же, как exec 3>&1здесь?
Wildcard
1
@ Wildcard Я подозреваю, что намеревался написать 3>&-здесь. 3>&1будет работать, но мало смысла. Спасибо
Стефан Шазелас
5

Вы можете использовать, tail -fчтобы держать fifo открытым после echoзаписи в него.

tail -n1 -f p1 | python

Почему это работает

pythonчитает от p1. Когда он достигает конца файла, он перестает читать. Это нормальное поведение для чтения файла, даже если файл является именованным каналом. tailс -fфлагом (follow) будет продолжать чтение из файла после достижения его конца.


источник
Я попытался echo "print \"Hello World\" " > p1во втором терминале, и ничего не случилось - но терминал также не был заблокирован. Терминал с python оставался заблокированным до тех пор, пока я ^cне выйду из него и не завершу работу python с сообщением о прерывании клавиатуры, отображаемым python.
Лорд Ло.
Я использовал этот tail -fтрюк при распаковке архива tar с разделением на блоки по именованному каналу. Это сработало чудесно.
Mael
2

Вам необходимо отправить всю программу сразу.

Когда вы вызываете run, python < p1оболочка ожидает ввода перед вызовом python. То есть, питон не даже начать выполнение на всех , пока весь поток данных не считан оболочкой , а затем передается в полном объеме в python.

Даже при запуске python -u p1вместо этого (то есть без буферизации и чтения из файла p1) pythonбудет пытаться прочитать весь файл, прежде чем он выполнит какой-либо из них.

Попробуйте этот эксперимент.

Терминал 1:

mkfifo p1
python < p1

Терминал 2:

cat > p1
print "Hello World"
print "Hello World"

Вы увидите, что можете отправлять несколько строк, но Python в термине 1 ничего не делает. Теперь нажмите ctrl+ D. Вся программа выполняется сразу.

Итак, подведем итог: если вы хотите, чтобы python читал из канала, вам нужно отправить всю программу. Вы не можете использовать Python в интерактивном режиме таким образом.

bahamat
источник
1

Может быть, хвостовой подход лучше (более гибкий), но в качестве альтернативы:

{ echo -n "print \"Hello World\""; cat; } > p1
Хауке Лагинг
источник
Это не работает, как я хочу. -nможет быть, о будет удален. И после этого 0. Терминал с echoкомандой блокируется 1. Python не выполняет команду, пока я не нажму ^cв echoтерминале и оба процесса не завершатся.
Лорд Ло.
1
@LordLoh. Может быть проблема буферизации. Вероятно, python выполнит команду, если будет создано достаточно выходных данных, чтобы первая строка наконец была записана в FIFO. Но поскольку есть рабочее решение, не имеет смысла прилагать усилия для решения этой проблемы.
Хауке Лагинг