获取 Python 以在交互式 Perl 脚本中模拟用户输入
Getting Python to emulate user inputs in an interactive Perl script
我是编程新手,这个问题已经解决了一段时间...
我正在编写一个 Python 脚本来自动执行基于交互式命令行的 Perl 脚本,以便它可以 运行 在指定目录中的每个文件上。我可以让程序使用 subprocess.call
和 subprocess.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 打印到 stdout
和 stderr
的内容。你可能需要这些。
给定目录中每个文件的运行命令:
#!/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
请参阅 了解当前代码失败的原因。
我是编程新手,这个问题已经解决了一段时间...
我正在编写一个 Python 脚本来自动执行基于交互式命令行的 Perl 脚本,以便它可以 运行 在指定目录中的每个文件上。我可以让程序使用 subprocess.call
和 subprocess.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 打印到 stdout
和 stderr
的内容。你可能需要这些。
给定目录中每个文件的运行命令:
#!/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
请参阅