【问题标题】:sending many commands to cmd向 cmd 发送许多命令
【发布时间】:2016-11-14 14:17:06
【问题描述】:

我正在尝试根据他发送给我的答案发送cmd许多命令。

我收到一条运行时错误消息:

ValueError: I/O operation on closed file

当我运行这样的事情时:

import subprocess
process = subprocess.Popen("cmd.exe", stdout=subprocess.PIPE,stdin=subprocess.PIPE)
answer = process.communicate(input="some command\n" + '\n')[0]

"""
choosing another command according to answer
"""

print process.communicate(input=another_command + '\n')[0]
process.kill()

知道如何解决这个问题吗?

感谢您的帮助!

【问题讨论】:

  • 您能提供更大的图景吗?你是在process.kill() 之后发送命令吗?如果没有,您能否提供一些代码示例(使用真实命令而不是"some command")?您尝试在 cmd 中运行的命令有可能会终止您的 shell。
  • 即使没有process.kill() 并且两个命令都为"ipconfig\n"。第一个命令正在运行,第二个命令给了我运行时错误
  • 执行命令可能会发送返回码,关闭 Popen 对象。例如,如果您执行 ipconfig 然后执行process.poll(),您可能会看到0 返回码。
  • 是的,它显示0,有什么办法可以避免关闭Popen object

标签: python windows cmd subprocess runtime-error


【解决方案1】:

不要将您的命令发送到 cmd.exe。像这样直接调用你的命令:

subprocess.Popen("dir", shell=True, stdout=subprocess.PIPE,stdin=subprocess.PIPE)

如果你以这种方式使用它,也许你不需要管道用于标准输入。

【讨论】:

  • 如果我想用sub-processingcommunicate() 来做,这可能吗?非常感谢您的帮助!
  • @EyalS 您的任务是使用子处理和通信()还是解决特殊问题?您可以使用通信将输入通过管道传输到交互式命令中。但我认为您不能使用它将命令通过管道传递给 cmd。
  • 由于某种原因,即使我的所有路径都完全正确,我的计算机也无法将 cmd.exe 识别为系统程序,这导致我尝试使用子处理绕过问题,
  • 不,当我尝试时,我收到了这样的错误WindowsError: [Error 2] The system cannot find the file specified
  • @EyalS,dir 命令内置在 cmd.exe 中。没有dir.exe。对于shell=TruePopen 执行的实际命令行是C:\Windows\System32\cmd.exe /c "dir"。我通过“自定义命令”假设 jhinghaus 是指外部命令,例如 ipconfig.exepython.exe
【解决方案2】:

错误是正常的。 communicate 关闭子进程的标准输入以指示没有更多输入待处理,以便子进程可以刷新其输出。因此,您不能在一个子进程上链接多个 communicate 调用。

但是如果你的命令足够简单(输入数据不是很多kbytes),并且如果你不需要在发送下一个命令之前收集和处理一个命令的输出,你应该能够将所有命令写在序列,在其中两个之间读取尽可能多的输出。在最后一个命令之后,您可以关闭子进程标准输入并等待它终止,仍然在整理输出:

process = subprocess.Popen("cmd.exe", stdout=subprocess.PIPE, stdin=subprocess.PIPE)
process.stdin.write("some command\n\n")
partial_answer = process.stdout.read()  # all or part of the answer can still be buffered subprocess side
...
process.stdin.write("some other command\n\n")
...
# after last command, time to close subprocess
process.stdin.close()
retcode = None
while True:
    end_of_answer += process.stdout.read()
    if retcode is not None: break

【讨论】:

  • 如果您没有使用专用的阅读器线程,请注意死锁。在 Windows 中,您可以使用来自 msvcrt.get_osfhandle(process.stdout.fileno()) 的句柄调用 PeekNamedPipe 来获取可用字节数。这样,您就不会在尝试读取更多可用数据时陷入僵局,而 cmd.exe 被阻止等待标准输入上的命令。对于使用 shell,您还可以设置自定义提示并一次读取一个字节,直到读取提示为止。
  • 另外,如果您不想重复调用flush,请传递bufsize=0 以防止缓冲process.stdin,并且cmd.exe 需要以"\r\n" 结尾的行,而不是"\n\n".
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-05-22
  • 2014-07-31
  • 2013-11-05
  • 2017-06-06
  • 2012-07-30
  • 1970-01-01
相关资源
最近更新 更多