将python脚本中的shell命令输出保存到text-fi

2024-10-01 22:39:53 发布

您现在位置:Python中文网/ 问答频道 /正文

我设法在python脚本中调用并使用一个终端命令,它在其中工作。在

但目前我试图将这个命令的“output”结果保存到一个文本文件中,但是我得到了错误。在

这是我的初始代码,它在其中正确运行:

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

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

^{pr2}$

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

当我在网上发现这个时,我确实关闭了这个文件。我错在哪里了?在


Tags: 代码import命令脚本终端outputos错误
1条回答
网友
1楼 · 发布于 2024-10-01 22:39:53

其中的Python编程部分更适合于stackoverflow.com网站. 不过,还有一个面向Unix的组件。在

每个文件都有三个已知的描述符。虽然它们的名称是stdin、stdout和stderr,但它们实际上是通过它们的文件数字来知道的,它们分别是0、1和2。要运行一个程序并捕获它的stdout-file-number-1输出,您必须将该进程的file-descriptor-1连接到一个文件或管道。在

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

prog > file

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

  1. 打开文件。这将产生一个开放文件描述符,其数量可能大于2,因为0到2是您自己的stdin、stdout和stderr。在
  2. 使用fork系统调用或它的一个变体:这是你自己的克隆。在
  3. 在克隆中(而不是在原始文件中),将文件描述符从现在所在的位置移动到文件描述符1。然后关闭原始编号更高的描述符(以及您打开的、不希望传递的任何其他描述符)。在
  4. 使用exec调用家族中的一个来终止您自己(克隆),但在此过程中,请将所有内容替换为程序prog。这将维护所有打开的文件描述符,包括指向在步骤3中移动的文件或管道的描述符。一旦exec成功,您就不再存在,也无法做任何事情。(如果exec失败,则报告失败并退出。)
  5. 回到原始(父进程)进程中,等待克隆子进程执行完毕,或者失败,或者发生任何情况。在

Python就是这样,这个多步骤的序列在subprocess模块中为您包装好了,并进行了奇特的错误检查。您可以使用os.system,而不是使用subprocess.Popen。它的设计目的是使用比文件更困难的管道,因此如果您真的想重定向到一个文件,而不是简单地通过管道读取程序的输出,那么您应该先打开文件,然后调用subprocess.Popen。在

在任何情况下,改变Python进程的sys.stdout都没有帮助,因为sys.stdout是一个非常独立于底层文件描述符系统的Python数据结构。通过对Python流进行open,您确实获得了一个文件描述符(以及一个Python数据结构),但它不是file-descriptor-number-1。无论底层文件描述符编号是什么,都必须在克隆中的fork调用后移动到slot-1位置。即使使用subprocess.Popen,Python唯一要移动的描述符post fork就是作为stdout=参数传递的描述符。在

(子流程的Popen接受以下任何一个:

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

这个库非常花哨,并且知道如何使用Python回溯来报告exec失败,或者子系统中发生的各种其他故障。它使用另一个带有close on exec的辅助管道来完成此操作。此管道上的EOF意味着exec成功;否则到达这个额外管道的数据包括失败,使用pickle模块转换为字节流。)

相关问题 更多 >

    热门问题