在 subprocess.Popen 中使用 && 进行命令链接?

9

我正在使用Pythonsubprocess.Popen,但我还没有找到优雅地通过Popen连接命令(即foobar&&bizbang)的解决方案。

我可以这样做:

p1 = subprocess.Popen(["mmls", "WinXP.E01"], stdout=subprocess.PIPE)
result = p1.communicate()[0].split("\n")
for line in result:
    script_log.write(line)

script_log.write("\n")

p1 = subprocess.Popen(["stat", "WinXP.E01"], stdout=subprocess.PIPE)
result = p1.communicate()[0].split("\n")
for line in result:
    script_log.write(line)

但这真的不太美观(特别是如果我通过Popen串联多个命令。


我希望尽可能少地使用命令块来复制此输出。

not@work ~/ESI/lab3/images $ mmls WinXP.E01 && echo -e "\n" && stat WinXP.E01
DOS Partition Table
Offset Sector: 0
Units are in 512-byte sectors

     Slot    Start        End          Length       Description
00:  Meta    0000000000   0000000000   0000000001   Primary Table (#0)
01:  -----   0000000000   0000000062   0000000063   Unallocated
02:  00:00   0000000063   0020948759   0020948697   NTFS (0x07)
03:  -----   0020948760   0020971519   0000022760   Unallocated


  File: `WinXP.E01'
  Size: 4665518381  Blocks: 9112368    IO Block: 4096   regular file
Device: 14h/20d Inode: 4195953     Links: 1
Access: (0644/-rw-r--r--)  Uid: ( 1000/    nott)   Gid: ( 1000/    nott)
Access: 2013-03-16 23:20:41.901326579 -0400
Modify: 2013-03-04 10:05:50.000000000 -0500
Change: 2013-03-13 00:25:33.254684050 -0400
 Birth: -

有什么建议?

注意:我想避免在subprocess.Popen中键入此内容。

p1 = subprocess.Popen(["mmls WinXP.E01 && echo -e '\n' && stat WinXP.E01"], stdout=subprocess.PIPE)

当你说“chaining”时,你只是指按顺序运行进程,对吗?不是像使用管道一样将一个程序的输出传递给下一个程序的输入吧?如果是这样,那么编写一个函数来运行一系列程序并返回一个字符串(或行列表)以组合输出应该很容易。只需制作一个循环即可! - Blckknght
2个回答

9

&& 是一个shell运算符,在默认情况下Popen不使用shell。

如果您想使用shell功能,请在Popen调用中使用shell=True,但要注意它会略微降低速度/增加内存使用量。

p1 = subprocess.Popen(["mmls", "WinXP.E01", "&&", "echo", "-e", "\"\n\"", "&&", "stat", "WinXP.E01"],
                      stdout=subprocess.PIPE, shell=True)

有没有更好的解决方案,既不会很慢,也不会占用太多内存? - user1260503
1
在你的示例中,可以执行两个单独的命令,或将它们放置在一个循环中。 - Matt
2
警告!使用shell也是一个重大的安全风险。如果可能的话,请避免使用!链接 - Connor
在这种情况下如何避免?我觉得这个问题基本上没有得到回答,但我不知道答案。 - Jonathan Rayner

2
这个怎么样:
from subprocess import Popen, PIPE

def log_command_outputs(commands):
    processes = [Popen(cmd, stdout=PIPE) for cmd in commands]
    outputs = [proc.communicate()[0].split() for proc in processes]
    for output in outputs:
        for line in output:
            script_log.write(line)
        script_long.write("\n")

这会并行地开始执行命令,可能比一个接一个地执行快一点(但可能并不明显)。由于 communicate 调用是顺序的,所以任何有大量输出的命令(超过管道缓冲区)将阻塞直到轮到它被清理为止。

对于您的示例命令链,您应该调用:

log_command_outputs([["mmls", "WinXP.E01"], ["stat", "WinXP.E01"]])

'&&' shell 运算符用于仅在前一个命令成功时调用下一个命令。通常这是因为下一个命令依赖于前一个命令的输出。在这种情况下,同时运行命令将无法按预期工作。 - Alex Che

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接