プロセスの標準入力への書き込み


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は、キーボードからデータが入力されたかのように、端末のstdinに書き込むことができます。たとえば、github.com
thrig

回答:


9

この方法でシェル/インタープリターに入力を送信することは、非常に問題が発生しやすく、信頼できる方法で作業することが非常に困難です。

適切な方法はソケットを使用することです。これがソケットが発明された理由です。これを使用して、ncat ncまたはsocatpythonプロセスを単純なソケットにバインドするコマンドラインで実行できます。または、ポートにバインドし、ソケットで解釈するコマンドをリッスンする単純なpythonアプリケーションを作成します。

ソケットはローカルにすることができ、Webインターフェースに公開されません。


問題python、コマンドラインから開始すると、通常、ターミナルに接続されているシェルに接続されていることです。実際、

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

そのためstdin、Pythonで書き込むときは、実際ptyには、単純なファイルではなく、カーネルデバイスである疑似端末に書き込んでいます。ioctlnot readおよびを使用しているwriteため、画面に出力が表示されますが、生成されたプロセス(python)には送信されません。

試行しているものを複製する1つの方法は、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 2017

@roaimaあなたが正しい、私はエコーがストリームを閉じるときにEOFを送信するという私の理解で誤っていました。これは|パイプでは回避できませんが、正しいですか?
クレイジー

私はすでにfifoの道を進んでecho something > fifoいましたが、EOFが発生し、多くのアプリケーションが停止しました。sleep infinity > fifo回避策は、しかし、私の半ばを越えていなかった、ありがとうございました!
シェッピー2017

1
実際にあなたのアイデアをpython -i <> fifo
続ければ

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

Pythonは端末に対して読み取りと書き込みの両方を行います。を実行すると、ターミナルにecho 'print "Hello"' > /proc/$(pidof python)/fd/0書き込みますprint "Hello"print "Hello"指示どおりに端末が表示されます。Pythonプロセスは何も表示せず、まだ入力を待っています。

入力をPythonプロセスにフィードしたい場合は、ターミナルにそれを実行させる必要があります。その方法については、crasicの答えを参照してください。


2

何のオフ構築ジルが言った、我々は端末に接続されたプロセスの標準入力に書き込みたい場合は、私たちが実際に端末に情報を送信する必要があります。ただし、ターミナルは入力と出力の形式として機能するため、ターミナルに書き込む場合、ターミナルでは、「画面」ではなく、ターミナル内で実行されているプロセスに書き込むことを認識できません。

ただし、Linuxには、TIOCSTI(ターミナルI / O制御-端末入力のシミュレーション)というioctlリクエストを介してユーザー入力をシミュレートする非posixの方法があり、ユーザーが入力したかのように文字を端末に送信できます。

私はこれがどのように機能するかを表面的にしか認識していませんが、この答えに基づいて、

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を完全に削除する方が「より安全」であると考えました。しかし、私はこれらのいずれにもあまり慣れていないので、特定のシステムでの経験がないときは、そのシステムで何かができないと言った方がいいと思いました。
クリスチャンレアールフルハーティ
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.