Запись в стандартный ввод процесса

# screen -S old_session_name -X sessionname new_session_name
9
24.11.2018, 17:19
3 ответа

Отправка входных данных оболочкам/интерпретаторам таким способом чревата -большими проблемами, и очень трудно заставить работать каким-либо надежным способом.

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

сокеты могут быть локальными и не открываться никакому веб-интерфейсу.


Проблема заключается в том, что если вы запускаете pythonиз командной строки, она обычно прикрепляется к вашей оболочке, которая подключена к терминалу, на самом деле мы можем видеть

$ ls -al /proc/PID/fd
lrwxrwxrwx 1 USER GROUP 0 Aug 1 00:00 0 -> /dev/pty1

поэтому, когда вы пишете в stdinPython, вы на самом деле пишете в терминал ptypsuedo -, который является устройством ядра, а не простым файлом. Он использует 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
11
27.01.2020, 20:05

Доступ к /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 , чтобы узнать, как это сделать.

16
27.01.2020, 20:05

Опираясь на то, что Жиль сказал , если мы хотим записать в стандартный ввод процесса, который подключен к терминалу, нам фактически нужно отправить информацию на терминал. Однако, поскольку терминал служит формой ввода, а также вывода, при записи в него терминал не может знать, что вы хотите писать в процесс, работающий внутри него, а не на «экран».

Однако в 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]))

Некоторые внешние ресурсы:

http://man7.org/linux/man-pages/man2/ioctl.2.html

http://man7.org/linux/man-pages/man2/ioctl_tty.2.html

2
27.01.2020, 20:05

Теги

Похожие вопросы