将python脚本中的shell命令输出保存到文本文件中

时间:2017-03-18 00:59:42

标签: terminal python

我设法在我的python脚本中调用并使用终端命令,它正在运行。

但是目前我正在尝试将此命令的“输出”结果保存到文本文件中,但是我收到了错误。

这是我正确执行的初始代码:

import os
os.system("someCmds --proj ARCH --all")

我尝试将输出保存到文本文件时使用的代码:

import os
import sys
sys.stdout=open("output.txt","w")
command = os.system("someCmds --proj ARCH --all")
print command
sys.stdout.close()

但是我收到以下错误 - ValueError: I/O operation on closed file

我在网上发现了这个文件。那我错在哪里?

1 个答案:

答案 0 :(得分:2)

这对Python编程部分更适合stackoverflow.com。但是,也有一个面向Unix的组件。

每个进程都有三个众所周知的文件描述符。虽然它们有name-stdin,stdout和stderr,但实际上它们的文件 numbers 分别为0,1和2。要运行程序并捕获其stdout-file-number-1输出,必须将该进程的文件描述符-1连接到文件或管道。

在命令行shell中,有以下语法:

prog > file

在一个进程中运行程序prog,该进程的stdout连接到已移入descriptor-slot-1的打开的文件描述符。实际上,在系统调用级别上发生的所有事情都很复杂:

  1. 打开文件。这会产生一个打开的文件描述符,其数量可能高于2,因为从零到两个是你自己的stdin,stdout和stderr。
  2. 使用fork系统调用或其中一个变体:这样可以克隆自己。
  3. 在克隆中(但不是在原始文件中),将文件描述符从现在的任何地方移动到文件描述符1.然后关闭原始的更高编号的描述符(以及您的任何其他描述符)打开,你不想传递。)
  4. 使用其中一个exec系列调用来终止自己(克隆),但在此过程中,使用程序prog替换所有内容。这将保留所有打开的文件描述符,包括指向您在步骤3中移动的文件或管道的描述符。一旦exec成功,您就不再存在且无法执行任何操作。 (如果exec 失败,请报告失败并退出。)
  5. 返回原始()进程,等待clone-child执行,然后完成,或者失败,或者发生的任何事情。
  6. Python就是这样,这个多步骤序列全部包含在subprocess模块中的花哨错误检查中。您可以使用os.system,而不是使用subprocess.Popen。它设计用于管道 - 实际上比文件更难 - 所以如果你真的想要重定向到文件,而不是简单地通过一个读取程序的输出管道,您将首先打开文件,然后调用subprocess.Popen

    在任何情况下,更改Python进程的sys.stdout都没有用,因为sys.stdout是一个完全独立于底层文件描述符系统的Python数据结构。通过open Python流,您可以获得文件描述符(以及Python数据结构),但它不是文件描述符编号-1。无论是什么,基础文件描述符号都必须移动到克隆中 fork调用之后的<1>位置。即使您使用subprocess.Popen,Python将移动的唯一描述符(post-fork)也是您作为stdout=参数传递的描述符。

    (子流程&#39; s Popen接受以下任何一项:

    • Python流:Python使用stream.fileno()来获取描述符编号,或
    • 一个整数:Python假定这表示一个应该移动到fd 0,1或2的打开文件描述符,具体取决于这是stdin=stdout=还是{{stderr=的参数。 1}},或
    • 特殊值subprocess.PIPE或者,对于stderr=subprocess.STDOUT:这些告诉它Python应该创建一个管道,或者重新使用先前创建的stdout管道来处理特殊{ {1}}案例。

    该库非常华丽,并且知道如何使用Python回溯报告stderr=subprocess.STDOUT失败或子进程中发生的各种其他失败。它使用另一个具有close-on-exec的辅助管道来完成此操作。此管道上的EOF表示执行成功;否则到达此额外管道的数据包括失败,使用exec模块转换为字节流。)