使用 PIPE 打开的子进程仍在从终端读取输入
Subprocess opened with PIPE still reading input from terminal
Python应用程序
我的 Python 3.6.8 应用程序 运行s 在 CentOS 7.6 上,并且:
- 使用 Kivy 11.1.1 提供 GUI。
- 打开别人的子流程。
- 子流程提供自定义shell。
- 当使用如下管道打开时,子进程仍然从终端读取。
- 它忽略我的应用程序对标准输入的命令。
- 但我的应用确实通过管道从子进程接收输出。
子进程
- 子进程控制设备。
- 它通常提供交互式 shell。
- 我需要从我的应用程序控制它。
- 为了启动它,我调用了一个已编译的二进制文件。
- 它使用了一些 Perl 模块。
- 我不知道它的工作原理。
打开命令
我使用以下命令从主线程启动子进程:
launch_cmd = "{} {} {} {}".format(path_of_compiled_binary, opt1, opt2, opt3)
self.myproc = subprocess.Popen(launch_cmd.split(), shell=False,
cwd=self.testing_dir, close_fds=True, stdin=subprocess.PIPE,
stdout=subprocess.PIPE, stderr=subprocess.STDOUT, env=env,
bufsize=1, universal_newlines=True, preexec_fn=self.ignore_sigint)
写入命令
我尝试给子进程命令
cmd = self.generate_cmd()
cmd = cmd + "\n"
bytes_sent = self.myproc.stdin.write(cmd)
self.myproc.stdin.flush()
- 数字bytes_sent符合预期
- 子进程忽略此输入。
- 但是如果在启动我的应用程序的终端中输入,它会执行相同的命令。
文件描述符
- 如上启动时,子进程最终具有这些文件描述符。
- 这是我需要它来运行我的命令的阶段:
`
lr-x------. 1 demo demo 64 Jun 5 10:44 0 -> pipe:[58635]
l-wx------. 1 demo demo 64 Jun 5 10:44 1 -> pipe:[58636]
l-wx------. 1 demo demo 64 Jun 5 10:44 2 -> pipe:[58636]
lr-x------. 1 demo demo 64 Jun 5 10:44 3 -> /dev/null
lr-x------. 1 demo demo 64 Jun 5 10:44 4 -> path_of_compiled_binary
lr-x------. 1 demo demo 64 Jun 5 10:44 5 -> /dev/tty
l-wx------. 1 demo demo 64 Jun 5 10:44 6 -> /dev/tty
lrwx------. 1 demo demo 64 Jun 5 10:44 7 -> socket:[59509]
lrwx------. 1 demo demo 64 Jun 5 10:44 8 -> /dev/ttyACM0
lr-x------. 1 demo demo 64 Jun 5 10:44 9 -> /tmp/par-64656d6f/temp-15579/inc/lib/PDL/IO/Pic.pm
子进程从 tty 读取,而不是 stdin
子进程打开2个文件描述符到/dev/tty:
lr-x------. 1 demo demo 64 Jun 5 10:44 5 -> /dev/tty
l-wx------. 1 demo demo 64 Jun 5 10:44 6 -> /dev/tty
- @that-other-guy 建议子进程从其中一个而不是标准输入中读取。
- 好像是5,因为它的模式是只读的?
/usr/bin/script实用程序
来自@that-other-guy 的另一个建议:
- 使用
script
启动子进程。
- script 实用程序旨在将 shell 会话捕获到实时记录中。
- -c 选项生成任何给定命令而不是 shell。
- 为文件参数提供 /dev/null 表示忘记成绩单。
使用脚本重新编码:
launch_cmd = "{} {} {} {}".format(path_of_compiled_binary, opt1, opt2, opt3)
script_argv = ["/usr/bin/script", "-c", launch_cmd, "/dev/null"]
self.myproc = subprocess.Popen(script_argv, shell=False,
cwd=self.testing_dir, close_fds=True, stdin=subprocess.PIPE,
stdout=subprocess.PIPE, stderr=subprocess.STDOUT, env=env,
bufsize=1, universal_newlines=True, preexec_fn=self.ignore_sigint)
工作原理
script
生成子进程并在伪终端中与其交互。
script
从管道中读取标准输入并将其回显到其伪终端以供子进程读取。
- 现在子进程是否在 5 上读取终端而不是在 0 上读取标准输入并不重要。
这个改动解决了这个问题。子进程现在从应用程序接收命令。
Python应用程序
我的 Python 3.6.8 应用程序 运行s 在 CentOS 7.6 上,并且:
- 使用 Kivy 11.1.1 提供 GUI。
- 打开别人的子流程。
- 子流程提供自定义shell。
- 当使用如下管道打开时,子进程仍然从终端读取。
- 它忽略我的应用程序对标准输入的命令。
- 但我的应用确实通过管道从子进程接收输出。
子进程
- 子进程控制设备。
- 它通常提供交互式 shell。
- 我需要从我的应用程序控制它。
- 为了启动它,我调用了一个已编译的二进制文件。
- 它使用了一些 Perl 模块。
- 我不知道它的工作原理。
打开命令
我使用以下命令从主线程启动子进程:
launch_cmd = "{} {} {} {}".format(path_of_compiled_binary, opt1, opt2, opt3)
self.myproc = subprocess.Popen(launch_cmd.split(), shell=False,
cwd=self.testing_dir, close_fds=True, stdin=subprocess.PIPE,
stdout=subprocess.PIPE, stderr=subprocess.STDOUT, env=env,
bufsize=1, universal_newlines=True, preexec_fn=self.ignore_sigint)
写入命令
我尝试给子进程命令
cmd = self.generate_cmd()
cmd = cmd + "\n"
bytes_sent = self.myproc.stdin.write(cmd)
self.myproc.stdin.flush()
- 数字bytes_sent符合预期
- 子进程忽略此输入。
- 但是如果在启动我的应用程序的终端中输入,它会执行相同的命令。
文件描述符
- 如上启动时,子进程最终具有这些文件描述符。
- 这是我需要它来运行我的命令的阶段:
`
lr-x------. 1 demo demo 64 Jun 5 10:44 0 -> pipe:[58635]
l-wx------. 1 demo demo 64 Jun 5 10:44 1 -> pipe:[58636]
l-wx------. 1 demo demo 64 Jun 5 10:44 2 -> pipe:[58636]
lr-x------. 1 demo demo 64 Jun 5 10:44 3 -> /dev/null
lr-x------. 1 demo demo 64 Jun 5 10:44 4 -> path_of_compiled_binary
lr-x------. 1 demo demo 64 Jun 5 10:44 5 -> /dev/tty
l-wx------. 1 demo demo 64 Jun 5 10:44 6 -> /dev/tty
lrwx------. 1 demo demo 64 Jun 5 10:44 7 -> socket:[59509]
lrwx------. 1 demo demo 64 Jun 5 10:44 8 -> /dev/ttyACM0
lr-x------. 1 demo demo 64 Jun 5 10:44 9 -> /tmp/par-64656d6f/temp-15579/inc/lib/PDL/IO/Pic.pm
子进程从 tty 读取,而不是 stdin
子进程打开2个文件描述符到/dev/tty:
lr-x------. 1 demo demo 64 Jun 5 10:44 5 -> /dev/tty
l-wx------. 1 demo demo 64 Jun 5 10:44 6 -> /dev/tty
- @that-other-guy 建议子进程从其中一个而不是标准输入中读取。
- 好像是5,因为它的模式是只读的?
/usr/bin/script实用程序
来自@that-other-guy 的另一个建议:
- 使用
script
启动子进程。 - script 实用程序旨在将 shell 会话捕获到实时记录中。
- -c 选项生成任何给定命令而不是 shell。
- 为文件参数提供 /dev/null 表示忘记成绩单。
使用脚本重新编码:
launch_cmd = "{} {} {} {}".format(path_of_compiled_binary, opt1, opt2, opt3)
script_argv = ["/usr/bin/script", "-c", launch_cmd, "/dev/null"]
self.myproc = subprocess.Popen(script_argv, shell=False,
cwd=self.testing_dir, close_fds=True, stdin=subprocess.PIPE,
stdout=subprocess.PIPE, stderr=subprocess.STDOUT, env=env,
bufsize=1, universal_newlines=True, preexec_fn=self.ignore_sigint)
工作原理
script
生成子进程并在伪终端中与其交互。script
从管道中读取标准输入并将其回显到其伪终端以供子进程读取。- 现在子进程是否在 5 上读取终端而不是在 0 上读取标准输入并不重要。
这个改动解决了这个问题。子进程现在从应用程序接收命令。