【问题标题】:Getting Python to emulate user inputs in an interactive Perl script让 Python 在交互式 Perl 脚本中模拟用户输入
【发布时间】:2016-01-14 17:11:30
【问题描述】:

我是编程新手,一直在努力解决这个问题......

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

我知道这是可能的,但我尝试了 1000 种不同的方法都无济于事。有人可以给我一个“像我 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,但这似乎不起作用。

非常感谢您的帮助。

【问题讨论】:

  • 当我想做这种事情时,我会在 shell 级别使用管道。
  • 您是只想将数据发送到子进程还是要从中读取数据?
  • 您确实意识到 Perl 程序可能会意识到它没有附加到 tty 并期望使用不同的格式,对吧?编辑 Perl 程序可能更容易
  • 多亏了这里发布的建议,我已经弄清楚了。结果(如我所料)我并不完全了解如何向 Perl 程序发送通信。

标签: python perl subprocess


【解决方案1】:

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

#!/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

请参阅@skmrx's answer,了解您当前代码失败的原因。

【讨论】:

    【解决方案2】:

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

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

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

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

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

    time.sleep(3)
    

    通常,逐行输入的脚本并不关心它们何时接收输入。所以你应该可以安全地删除它。

    Popen.communicate(input="1")
    

    再看documentation

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

    与进程交互:将数据发送到标准输入。从 stdout 和 stderr 读取数据,直到到达文件结尾。等待进程终止。

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

    【讨论】:

      猜你喜欢
      • 2013-12-20
      • 1970-01-01
      • 2013-01-18
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-05-29
      • 2021-09-04
      相关资源
      最近更新 更多