获取 Python 以在交互式 Perl 脚本中模拟用户输入

Getting Python to emulate user inputs in an interactive Perl script

我是编程新手,这个问题已经解决了一段时间...

我正在编写一个 Python 脚本来自动执行基于交互式命令行的 Perl 脚本,以便它可以 运行 在指定目录中的每个文件上。我可以让程序使用 subprocess.callsubprocess.Popen 启动,但是我要么从那里打开程序,然后它就在 shell 中等待用户输入,要么我打开它无数次。我需要 Perl 脚本为每个文件打开一次,接受用户输入(当然,在每次输入后按下类似于 "enter" 的东西,以及一个包含文件名的命令,应该是 str(files) 在下面的示例代码中),以用户输入 "4" 开始 Perl 脚本的计算,然后关闭它。

我知道这是可能的,但我尝试了 1000 种不同的方法都无济于事。有人可以给我一个 "explain it like I'm 5" 关于如何让这个 Python 和 Perl 脚本像用户输入命令一样相互交谈吗?

这是我目前的情况:

for files in os.listdir("In_Files"):
    print "Performing calculations on " + str(files) + " ..."
    os.chdir("/home/MTS/Dropbox/dir/In_Filess")
    subprocess.Popen("run_command.command -f a", shell=True) #this boots up the Perl script
    time.sleep(3) #waits for the script to open...
    Popen.communicate(input="1") #user inputs begin here
    Popen.wait(0) #am I trying to set a return value here so that the inputs may proceed once the previous one has been accepted?
    Popen.communicate(input=str(files)) #this is where the name of the file the Perl script is working on is entered
    Popen.wait(0)
    Popen.communicate(input="4")
    Popen.wait(0)

我一直在阅读很多关于标准输入管道的内容,但不太了解它们。它们是用于解决这个问题还是应该使用其他方法?另外,我已经看过 Pexpect,但它似乎不起作用。

非常感谢您的帮助。

管道是多个进程进行通信的一种方式,因此被广泛使用。管道是一对文件描述符,其中一个打开用于写入,另一个用于读取。如果数据写入前者,从后者读取将 return 返回相同的数据。

Popen 可以为其执行的进程的标准输入 (stdin)、标准输出 (stdout) 和标准错误 (stderr) 文件描述符创建管道 - 但您必须明确要求它。这样,您可以向 stdin 管道写入一些内容,这些管道将传递给 child 的 stdin。同样,如果要读取 child 进程的输出,可以从 stdout 管道读取。这很好地满足了您的目的,因此您的方法是正确的。

现在让我们看看您的代码:

subprocess.Popen("run_command.command -f a", shell=True)

这将执行命令,但不会创建管道以允许与 child 进程进行通信。如果您查看 documentation,它表示您需要明确要求它通过关键字参数创建管道,例如 stdin=subprocess.PIPE.

time.sleep(3)

通常,接受输入的脚本 line-by-line 不关心它们何时收到输入。所以你应该能够安全地删除它。

Popen.communicate(input="1")

再看看documentation

Popen.communicate(input=None, timeout=None)

Interact with process: Send data to stdin. Read data from stdout and stderr, until end-of-file is reached. Wait for process to terminate.

您只能调用 communicate() 一次并且您必须将所有输入作为一个字符串传递,并且它 return 是 child 进程终止后打印的数据。这也意味着对 wait() 的调用是不必要的。请注意,communicate() return 是一个元组,其中包含 child 打印到 stdoutstderr 的内容。你可能需要这些。

给定目录中每个文件的运行命令:

#!/usr/bin/env python
import os
from subprocess import Popen, PIPE

working_dir = b"/home/MTS/Dropbox/dir/In_Files"
for filename in os.listdir(working_dir):
    print("Performing calculations on {filename!r}...".format(**vars()))
    p = Popen(["run_command.command", "-f", "a"], cwd=working_dir, stdin=PIPE)
    p.communicate(input=b"\n".join([b"1", filename, b"4"]))
    if p.returncode != 0: # non-zero exit status may indicate failure
        raise Error

请参阅 了解当前代码失败的原因。