Python tar 使用 shell 无效

Python tar using shell not working

我正在尝试 tar 一些具有以下模式的文件:

/var/lib/cassandra/data/*/*/snapshots/<snapid>/

如果我手动执行 tar 命令,它可以正常工作,但是当我使用 python 执行它时,它会失败。

我执行如下:

    output = subprocess.check_output(["tar","cf", outputfile, snappath])

但是当我收到以下错误时,我可以 tar 手动文件

tar: /var/lib/cassandra/data/*/*/snapshots/20151215104608: Cannot stat: No such file or directory
tar: Exiting with failure status due to previous errors
Traceback (most recent call last):
  File "./cassandrabackup2s3.py", line 68, in <module>
    create_snapshot_file(snapid)
  File "./cassandrabackup2s3.py", line 46, in create_snapshot_file
    output = subprocess.check_output(["tar","cf", outputfile, snappath])
  File "/usr/lib64/python2.7/subprocess.py", line 575, in check_output
    raise CalledProcessError(retcode, cmd, output=output)
subprocess.CalledProcessError: Command '['tar', 'cf', '/tmp/20151215104608.tgz', '/var/lib/cassandra/data/*/*/snapshots/20151215104608/']' returned non-zero exit status 2

我看到一些关于从 -cvzf 中删除“-”或使用 shell=True 的帖子,但没有任何效果。这是使用 Shell=True

的输出
 output = subprocess.check_output(["tar","cf", outputfile, snappath], shell=True)

tar 的语法似乎不正确:

tar: You must specify one of the `-Acdtrux' or `--test-label'  options
Try `tar --help' or `tar --usage' for more information.
Traceback (most recent call last):
  File "./cassandrabackup2s3.py", line 68, in <module>
    create_snapshot_file(snapid)
  File "./cassandrabackup2s3.py", line 46, in create_snapshot_file
    output = subprocess.check_output(["tar","cf", outputfile, snappath], shell=True)
  File "/usr/lib64/python2.7/subprocess.py", line 575, in check_output
    raise CalledProcessError(retcode, cmd, output=output)
subprocess.CalledProcessError: Command '['tar', 'cf', '/tmp/20151215103816.tgz', '/var/lib/cassandra/data/*/*/snapshots/20151215103816/']' returned non-zero exit status 2

我试过使用 tar 库,但 * 之类的正则表达式似乎不起作用

我建议改用 tarfile 库:https://docs.python.org/2/library/tarfile.html

编辑给你举个例子:

import glob
import tarfile
snaps = glob.glob("/var/lib/cassandra/data/*/*/snapshots/<snapid>/")
with tarfile.open("tared.tar","w") as tar:
    for snap in snaps:
         tar.add(snap)

当你在命令行上运行tar,那么路径:

/var/lib/cassandra/data/*/*/snapshots/<snapid>/

shell 扩展,而不是由 tar 命令扩展。 check_output 不会进行 * 扩展,所以你需要 shell=True 是对的,这样 shell 就可以扩展这些变量。

但是,要使用 shell,您应该给子进程函数一个字符串,而不是一个列表:

output = subprocess.check_output("echo my command is here", shell=True)

所以你的 tar 命令,为了清楚起见,移到了单独的两行:

command = "tar cf {} {}".format(outputfile, snappath)
output = subprocess.check_output(command, shell=True)

正如@radek所说,您还可以使用tar模块:https://docs.python.org/2/library/tarfile.html

当您在 shell 提示符下 运行 此命令时,shell 会扩展通配符。如果要Python做通配符扩展,需要单独索取

从你的问题中不清楚哪个部分不起作用,但我想你想要

cmd = ['tar', 'cf', outputfile]
cmd.extend(glob.glob(snappath))
output = subprocess.check_output(cmd)

如果您没有使用 subprocess 的参数列表,添加 shell=True 会解决您的问题;那么 shell 将解析字符串并执行通配符扩展。但是当您提供一个列表时,shell=True 什么都不做,因为您(假设)已经执行了 shell 将执行的命令行解析。但一般来说,如果您的需求很简单,您应该避免使用 shell=True,因为 shell 本身会带来一些您需要注意的复杂情况。