有没有办法在Python中使用subprocess模块执行管道命令,而不使用shell=True?

12 投票
4 回答
10042 浏览
提问于 2025-04-16 08:07

我想在Python中运行一个Linux/bash的命令,这个命令首先会把文件打包成一个tar文件,然后再把这个tar文件分割开。这个命令在bash中大概是这样的:

> tar -cvf - path_to_archive/* | split -b 20m -d -a 5 - "archive.tar.split"

我知道我可以使用subprocess模块来执行这个命令,只需要把shell设置为True,然后把整个命令作为一个字符串提交,像这样:

import subprocess    

subprocess.call("tar -cvf - path_to_archive/* | split -b 20m -d -a 5 - 'archive.tar.split'", shell=True)

...但是出于安全考虑,我想找到一种方法来跳过“shell=True”这个部分(这个部分需要一个字符串列表,而不是完整的命令行字符串,并且不能正确处理管道符号)。在Python中有没有什么解决方案?也就是说,有没有办法以某种方式设置连接的管道,或者其他的解决方案?

4 个回答

2

有没有什么原因让你不能使用tarfile? | http://docs.python.org/library/tarfile.html

import tarfile
tar = tarfile.open("sample.tar.gz")
tar.extractall()
tar.close()

只需像使用文件一样使用tarfile,而不是调用子进程。

25

如果你想避免使用shell=True这个选项,可以手动使用subprocess管道

from subprocess import Popen, PIPE
p1 = Popen(["tar", "-cvf", "-", "path_to_archive"], stdout=PIPE)
p2 = Popen(["split", "-b", "20m", "-d", "-a", "5", "-", "'archive.tar.split'"], stdin=p1.stdout, stdout=PIPE)
output = p2.communicate()[0]

需要注意的是,如果你不使用shell,就无法使用像*这样的通配符来匹配文件名。不过,你可以使用glob这个模块来实现类似的功能。

3

tar可以自己分割:

tar -L 1000000 -F name-script.sh cf split.tar largefile1 largefile2 ...

name-script.sh

#!/bin/bash
echo "${TAR_ARCHIVE/_part*.tar/}"_part"${TAR_VOLUME}".tar >&"${TAR_FD}"

重新组合

tar -M -F name-script.sh cf split.tar

把这个加到你的Python程序里。

撰写回答