bash 有什么方法可以使用子进程模块在 Python 中执行管道命令,而不使用 shell=True?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/4368818/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-17 23:03:01  来源:igfitidea点击:

Any way to execute a piped command in Python using subprocess module, without using shell=True?

pythonbash

提问by Samuel Lampa

I want to run a piped command line linux/bash command from Python, which first tars files, and then splits the tar file. The command would look like something this in bash:

我想从 Python 运行一个管道命令行 linux/bash 命令,它首先 tars 文件,然后拆分 tar 文件。该命令在 bash 中看起来像这样:

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

I know that I could execute it using subprocess, by settings shell=True, and submitting the whole command as a string, like so:

我知道我可以使用子进程执行它,通过设置 shell=True,并将整个命令作为字符串提交,如下所示:

import subprocess    

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

...but for security reasons I would like to find a way to skip the "shell=True" part, (which takes a list of strings rather than a full command line string, and which can not handle the pipe char correctly). Is there any solution for this in Python? I.e., is it possible to set up linked pipes somehow, or some other solution?

...但出于安全原因,我想找到一种方法来跳过“shell=True”部分(它采用字符串列表而不是完整的命令行字符串,并且无法正确处理管道字符)。在 Python 中是否有任何解决方案?即,是否可以以某种方式设置链接管道,或其他解决方案?

采纳答案by Brian

tar can split itself:

tar 可以自行分裂:

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

name-script.sh

名称脚本.sh

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

To re-assemble

重新组装

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

Add this to your python program.

将此添加到您的 python 程序中。

回答by Brent Newey

If you want to avoid using shell=True, you can manually use subprocess pipes.

如果您想避免使用 shell=True,您可以手动使用子进程管道

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]

Note that if you do not use the shell, you will not have access to expansion of globbing characters like *. Instead you can use the globmodule.

请注意,如果您不使用 shell,您将无法访问像 *. 相反,您可以使用该glob模块。

回答by Jakob Bowyer

Is there any reason you can't use tarfile? | http://docs.python.org/library/tarfile.html

有什么理由不能使用 tarfile 吗?| http://docs.python.org/library/tarfile.html

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

Just write like a file like object using tarfile rather than invoking subprocess.

只需像使用 tarfile 的对象一样编写文件,而不是调用子进程。

回答by houqp

Shameless plug, I wrote a subprocess wrapper for easier command piping in python: https://github.com/houqp/shell.py

无耻的插件,我写了一个子进程包装器,以便在 python 中更容易地进行命令管道:https: //github.com/houqp/shell.py

Example:

例子:

shell.ex("tar -cvf - path_to_archive") | "split -b 20m -d -a 5 - 'archive.tar.split'"