首页 > 解决方案 > tar 命令的子进程 Popen 和 shell=False 出错

问题描述

我有以下旨在缩小的简单python代码 /usr/bin/tar -czvf x002.tgz *.py

代码是:

import subprocess

base_dir = "/home/workspace/x002"
tar_file = "x002.tgz"
py_file = "*.py"
p = subprocess.Popen(["/usr/bin/tar", "-czvf", tar_file, py_file], cwd=base_dir, stdout=subprocess.PIPE,
                     stderr=subprocess.STDOUT,
                     shell=False)
results = []
while True:
    line = p.stdout.readline().decode('utf8').strip()
    if line == '' and p.poll() is not None:
        break
    else:
        results.append(line)

print(results)

py确认目录下存在文件base_dir,但是报错如下,不知道问题出在哪里,有大神帮忙看看吗?谢谢!

['tar: *.py: Cannot stat: No such file or directory', 'tar: Exiting with failure status due to previous errors', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '', '']

标签: python

解决方案


这个简单的代码将重现您面临的问题:

import subprocess

p = subprocess.Popen(
    ["ls", "*"],
    shell=False
)

问题是通配符*扩展是一个shellbashzsh)特性;tar之类的命令ls不明白。它在命令执行之前由 shell 评估(使用exec系统调用)。您可以通过提供shell=True. 它将导致 Python 使用 shell 来执行命令。在此处阅读更多相关信息:subprocess 中 'shell=True' 的实际含义

但是,最好shell=False在 Python 脚本中使用,因为这样可以避免产生额外的 shell。Python 有一个称为glob的等效功能,它可以做同样的事情。这将稍微改变编码风格,而不是考虑在 Python 的交互式 shell 中执行命令,而是考虑使用 Python 的变量、函数等特性来做同样的事情。


推荐阅读