【问题标题】:Python - How to call bash commands with pipe?Python - 如何使用管道调用 bash 命令?
【发布时间】:2011-11-11 12:54:49
【问题描述】:

我可以在 Linux 的命令行上正常运行这个:

$ tar c my_dir | md5sum

但是当我尝试用 Python 调用它时,我得到一个错误:

>>> subprocess.Popen(['tar','-c','my_dir','|','md5sum'],shell=True)
<subprocess.Popen object at 0x26c0550>
>>> tar: You must specify one of the `-Acdtrux' or `--test-label'  options
Try `tar --help' or `tar --usage' for more information.

【问题讨论】:

标签: python popen subprocess


【解决方案1】:

你必须使用subprocess.PIPE,另外,为了拆分命令,你应该使用shlex.split()来防止某些情况下的奇怪行为:

from subprocess import Popen, PIPE
from shlex import split
p1 = Popen(split("tar -c mydir"), stdout=PIPE)
p2 = Popen(split("md5sum"), stdin=p1.stdout)

但是要制作存档并生成其校验和,您应该使用 Python 内置模块 tarfilehashlib 而不是调用 shell 命令。

【讨论】:

  • tarfile 和 hashlib 会更好。但是我如何散列一个 tarfile 对象呢?
  • @Greg 不对 tarfile 对象进行哈希处理,使用 open() 像任何其他文件一样打开生成的文件,然后对其内容进行哈希处理。
  • 有道理。这有效,但我得到的哈希值与原始命令不同。这是意料之中的吗?
  • @Greg,这应该和tar -c mydir | md5sum 做同样的事情。也许您可以开始一个新问题,包括一个交互式终端会话,您可以在其中运行此命令、启动 Python,然后运行 ​​Python 命令并显示输出。
【解决方案2】:

好的,我不知道为什么,但这似乎有效:

subprocess.call("tar c my_dir | md5sum",shell=True)

有人知道为什么原始代码不起作用吗?

【讨论】:

  • 管道 |是 shell 理解的将命令输入和输出连接在一起的字符。这不是 tar 理解的参数,也不是命令。您正在尝试将所有内容作为 tar 命令的参数执行,除非您创建子 shell。
  • 之所以有效,是因为整个命令被传递给 shell 并且 shell 理解 |。 Popen 调用进程并直接传入参数。对于 Popen,这由 shell= 控制并传递一个字符串(不是列表)IIRC。
【解决方案3】:

你真正想要的是以shell命令作为参数运行一个shell子进程:

>>> subprocess.Popen(['sh', '-c', 'echo hi | md5sum'], stdout=subprocess.PIPE).communicate()
('764efa883dda1e11db47671c4a3bbd9e  -\n', None)

【讨论】:

【解决方案4】:
>>> from subprocess import Popen,PIPE
>>> import hashlib
>>> proc = Popen(['tar','-c','/etc/hosts'], stdout=PIPE)
>>> stdout, stderr = proc.communicate()
>>> hashlib.md5(stdout).hexdigest()
'a13061c76e2c9366282412f455460889'
>>> 

【讨论】:

    【解决方案5】:

    我会在 python v3.8.10 上试试你的:

    import subprocess
    proc1 = subprocess.run(['tar c my_dir'], stdout=subprocess.PIPE, shell=True)
    proc2 = subprocess.run(['md5sum'], input=proc1.stdout, stdout=subprocess.PIPE, shell=True)
    print(proc2.stdout.decode())
    

    关键点(如我在相关https://stackoverflow.com/a/68323133/12361522 的解决方案中的大纲):

    • subprocess.run()
    • 没有拆分 bash 命令和参数,即['tar c my_dir']["tar c my_dir"]
    • stdout=subprocess.PIPE 适用于所有进程
    • input=proc1.stdout 前一个输出到下一个输入的链
    • 启用外壳shell=True

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2023-03-24
      • 1970-01-01
      • 1970-01-01
      • 2012-08-30
      • 1970-01-01
      • 2013-11-24
      • 2016-11-17
      • 2020-12-20
      相关资源
      最近更新 更多