프로세스의 표준에 쓰기


10

내가 다음을 입력하면 이해하는 한 ...

 python -i

... python-interpreter는 이제 stdin에서 다음과 같이 동작합니다 (분명히).

 >>> print "Hello"
 Hello

내가 이렇게하면 같은 일을 할 것으로 기대합니다.

 echo 'print "Hello"' > /proc/$(pidof python)/fd/0

그러나 이것은 출력입니다 (실제 빈 줄).

 >>> print "Hello"
 <empyline>

나에게 이것은 다음과 같이 보였습니다. print "Hello"\n에 쓰고 썼지 만 stdout해석하지 않았습니다. 왜 작동하지 않고 작동하게하려면 어떻게해야합니까?


TIOCSTI ioctl은 마치 키보드에서 데이터가 입력 된 것처럼 터미널의 표준 입력에 쓸 수 있습니다 . 예를 들어 github.com/thrig/scripts/blob/master/tty/ttywrite.c
— roaima

답변:


9

이런 식으로 쉘 / 인터프리터에 입력을 보내는 것은 문제가 발생하기 쉽고 신뢰할 수있는 방식으로 작업하기가 매우 어렵습니다.

올바른 방법은 소켓을 사용하는 것입니다. 이것이 소켓이 발명 된 이유입니다. 명령 행에서 ncat nc또는 socat파이썬 프로세스를 간단한 소켓에 바인드하여 바인딩 할 수 있습니다 . 또는 포트에 바인딩하고 소켓에서 해석하는 명령을 수신하는 간단한 Python 애플리케이션을 작성하십시오.

소켓은 로컬 일 수 있으며 웹 인터페이스에 노출되지 않습니다.


문제 는 python명령 줄에서 시작하면 일반적으로 터미널에 연결된 셸에 연결되어 실제로 볼 수 있다는 것입니다

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

stdin파이썬으로 쓸 때 실제로 pty는 단순한 파일이 아니라 커널 장치 인 의사 터미널에 쓰는 것 입니다. ioctlnot 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

파이프를 열린 상태로 유지하면 (예 :) sleep 300 > python_i.pipe &다른 쪽이 닫히지 않고 python파이프 아래로 명령이 계속 적용됩니다. 에서 보낸 EOF가 없습니다 echo.
— roaima

@roaima 당신이 옳습니다. 나는 에코가 스트림을 닫을 때 EOF를 보내는 것으로 이해했습니다. |그러나 파이프로 는 피할 수 없지만 맞습니까?
— crasic

나는 이미 fifo 길 echo something > fifo을 가고 있었지만 많은 응용 프로그램을 중단시킬 수있는 EOF를 얻었습니다. sleep infinity > fifo해결하지만 내 중간 교차하지 않았다, 감사합니다!
— Sheppy

1
실제로 당신의 생각을 계속하면, 당신은 또한 python -i <> fifoEOF를 막을 수 있습니다
— Sheppy

10

액세스 하면 프로세스 PID 의 파일 디스크립터 0에 액세스 하지 않고 PID 가 파일 디스크립터 0에서 연 파일에 액세스 합니다. 이는 미묘한 차이이지만 중요합니다. 파일 디스크립터는 프로세스가 파일에 연결하는 것입니다. 파일 디스크립터에 쓰기는 파일이 열린 방법에 관계없이 파일에 씁니다./proc/PID/fd/0

일반 파일 인 경우 파일에 쓰면 파일이 수정됩니다. 데이터는 프로세스가 다음에 읽을 내용 일 필요는 없습니다. 프로세스가 파일을 읽는 데 사용하는 파일 디스크립터에 연결된 위치에 따라 다릅니다. 프로세스가 열리면 다른 프로세스와 동일한 파일을 얻지 만 파일 위치는 독립적입니다./proc/PID/fd/0/proc/PID/fd/0

파이프 인 경우 파이프에 쓰면 파이프 버퍼에 데이터가 추가됩니다. 이 경우 파이프에서 읽는 프로세스가 데이터를 읽습니다./proc/PID/fd/0

터미널 인 경우 터미널에 쓰면 데이터가 터미널에 출력 됩니다. 터미널 파일은 양방향입니다. 파일에 쓰면 데이터가 출력됩니다. 즉 터미널은 텍스트를 표시합니다. 단말기로부터 판독하는 것은 데이터를 입력하는데, 즉 단말기는 사용자 입력을 전송한다./proc/PID/fd/0

파이썬은 터미널에서 읽고 씁니다. 를 실행 하면 터미널에 echo 'print "Hello"' > /proc/$(pidof python)/fd/0쓰고 print "Hello"있습니다. print "Hello"지시에 따라 터미널이 표시 됩니다. 파이썬 프로세스는 아무것도 보지 못하고 여전히 입력을 기다리고 있습니다.

파이썬 프로세스에 입력을 제공하려면 터미널에서 입력을 수행해야합니다. 그렇게하는 방법 은 crasic의 답변 을 참조하십시오 .


2

Gilles가 말한 것을 바탕 으로 터미널에 연결된 프로세스의 표준 입력에 쓰려면 실제로 터미널에 정보를 보내야합니다. 그러나 터미널은 출력뿐만 아니라 입력 형식의 역할도하기 때문에 터미널에 쓸 때 터미널은 "화면"이 아닌 터미널 내에서 실행중인 프로세스에 쓰려고한다는 것을 알 수 없습니다.

그러나 리눅스는 TIOCSTI(터미널 I / O 제어-터미널 입력 시뮬레이션) 이라 불리는 ioctl 요청을 통해 사용자 입력을 시뮬레이션하는 비-포식 방법을 가지고있어 마치 사용자가 입력 한 것처럼 터미널에 문자를 보낼 수 있습니다.

나는 이것이 어떻게 작동하는지 피상적으로 만 알고 있지만 이 답변을 바탕 으로

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


질문이 특정 운영 체제에만 국한된 것이 아니며 TIOCSTI가 Linux에서 시작되지 않았 음을 관찰하십시오. 이 답변이 작성되기 거의 2 년 전에 사람들은 보안상의 이유로 TIOCSTI를 삭제하기 시작했습니다. unix.stackexchange.com/q/406690/5132
— JdeBP

@JdeBP 따라서 "Linux"를 지정합니다 (어디에서 시작했는지 확실하지는 않지만). 그리고 "사람들"은 당신이 BSD를 의미하는 것 같습니까? 필자가이 글을 썼을 때 읽은 내용에 따르면, 훨씬 오래된 구현에서는 패치 된 보안 위험이 있었지만 BSD는 여전히 ioctl을 완전히 삭제하는 것이 안전하다고 생각했습니다. 그러나 나는 이것에 매우 익숙하지 않으므로 해당 시스템에 대한 경험이 없으면 특정 시스템에서 무언가가 불가능하다고 말하지 않는 것이 좋습니다.
— Christian Reall-Fluharty
당사 사이트를 사용함과 동시에 당사의 쿠키 정책과 개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.