Отправка входных данных оболочкам/интерпретаторам таким способом чревата -большими проблемами, и очень трудно заставить работать каким-либо надежным способом.
Правильным способом является использование сокетов, поэтому они были изобретены, вы можете сделать это в командной строке, используяncat
nc
или socat
, чтобы связать процесс Python с простым сокетом. Или напишите простое приложение на Python, которое привязывается к порту и прослушивает команды для интерпретации в сокете.
сокеты могут быть локальными и не открываться никакому веб-интерфейсу.
Проблема заключается в том, что если вы запускаете python
из командной строки, она обычно прикрепляется к вашей оболочке, которая подключена к терминалу, на самом деле мы можем видеть
$ ls -al /proc/PID/fd
lrwxrwxrwx 1 USER GROUP 0 Aug 1 00:00 0 -> /dev/pty1
поэтому, когда вы пишете в stdin
Python, вы на самом деле пишете в терминал pty
psuedo -, который является устройством ядра, а не простым файлом. Он использует ioctl
, а не read
и write
, поэтому вы увидите вывод на своем экране, но он не будет отправлен порожденному процессу (python
)
Один из способов воспроизвести то, что вы пытаетесь сделать, — использовать fifo
или named pipe
.
# make pipe
$ mkfifo python_i.pipe
# start python interactive with pipe input
# Will print to pty output unless redirected
$ python -i < python_i.pipe &
# keep pipe open
$ sleep infinity > python_i.pipe &
# interact with the interpreter
$ echo "print \"hello\"" >> python_i.pipe
Вы также можете использовать screen
только для ввода
# start screen
$ screen -dmS python python
# send command to input
$ screen -S python -X 'print \"hello\"'
# view output
$ screen -S python -x
Доступ к /proc/PID/fd/0
не приводит к доступу к файловому дескриптору 0 процесса PID , он обращается к файлу, который PID открыл в файловом дескрипторе 0. Это тонкое различие, но это имеет значение. Файловый дескриптор — это соединение процесса с файлом. Запись в дескриптор файла записывается в файл независимо от того, как файл был открыт.
Если /proc/PID/fd/0
является обычным файлом, запись в него изменяет файл. Данные не обязательно являются тем, что процесс будет читать дальше :, они зависят от позиции, прикрепленной к файловому дескриптору, которую процесс использует для чтения файла. Когда процесс открывается /proc/PID/fd/0
, он получает тот же файл, что и другой процесс, но позиции файлов не зависят друг от друга.
Если /proc/PID/fd/0
является каналом, то запись в него добавляет данные в буфер канала. В этом случае процесс, читающий из канала, будет считывать данные.
Если /proc/PID/fd/0
является терминалом, то запись в него выводит данные на терминал. Файл терминала двунаправленный :запись в него выводит данные, т.е. терминал отображает текст; чтение с терминала вводит данные, то есть терминал передает пользовательский ввод.
Python выполняет как чтение, так и запись в терминал. Когда вы запускаете echo 'print "Hello"' > /proc/$(pidof python)/fd/0
, вы записываете print "Hello"
на терминал. Терминал отображает print "Hello"
в соответствии с инструкциями. Процесс python ничего не видит, он все еще ждет ввода.
Если вы хотите передать входные данные процессу Python, вы должны заставить терминал сделать это. См. ответ crasic , чтобы узнать, как это сделать.
Опираясь на то, что Жиль сказал , если мы хотим записать в стандартный ввод процесса, который подключен к терминалу, нам фактически нужно отправить информацию на терминал. Однако, поскольку терминал служит формой ввода, а также вывода, при записи в него терминал не может знать, что вы хотите писать в процесс, работающий внутри него, а не на «экран».
Однако в Linux есть не -posix способ имитации пользовательского ввода с помощью запроса ioctl, который называетсяTIOCSTI
(Terminal I/O Control -Simulate Terminal Input ), который позволяет нам отправлять символы на терминал, как если бы они были введены пользователем.
Я лишь поверхностно знаю, как это работает, но, основываясь на этом ответе, должно быть возможно сделать это с помощью чего-то вроде
import fcntl, sys, termios
tty_path = sys.argv[1]
with open(tty_path, 'wb') as tty_fd:
for line in sys.stdin.buffer:
for byte in line:
fcntl.ioctl(tty_fd, termios.TIOCSTI, bytes([byte]))
Некоторые внешние ресурсы: