将python中的双引号shell命令传递给subprocess.Popen()?

Posted

技术标签:

【中文标题】将python中的双引号shell命令传递给subprocess.Popen()?【英文标题】:Passing double quote shell commands in python to subprocess.Popen()? 【发布时间】:2013-02-02 10:39:54 【问题描述】:

我一直在尝试在命令行中围绕 ffmpeg 的 "concat:file1|file2" 参数传递一个仅使用文字双引号的命令。

但是,我无法使用 subprocess.Popen() 在 python 中完成这项工作。任何人都知道如何将引号传递给 subprocess.Popen?

代码如下:

command = "ffmpeg -i "concat:1.ts|2.ts" -vcodec copy -acodec copy temp.mp4"

output,error = subprocess.Popen(command, universal_newlines=True,
stdout=subprocess.PIPE,
stderr=subprocess.PIPE).communicate()

当我这样做时,ffmpeg 除了在 concat 段周围加上引号外,不会采取任何其他方式。有没有办法成功地将这一行传递给 subprocess.Popen 命令?

【问题讨论】:

不只是在你的命令周围使用“单引号”吗?如果您在终端上完全按照您所写的方式输入命令,那么处理这些引号的将是 shell,而不是 ffmpeg! 那是真的代码吗?当我在 Python 终端中输入command = "ffmpeg -i "concat:1.ts|2.ts" -vcodec copy -acodec copy temp.mp4" 时,我得到SyntaxError: invalid syntax...为什么,有趣...似乎子进程即使没有调用它也会做坏事... 您的 Python 代码有一个简单的语法错误,您可以使用如下的单引号进行纠正:command = 'ffmpeg -i "concat:1.ts|2.ts" -vcode copy -acodec copy temp.mp4' 【参考方案1】:

您问题中的这行代码不是有效的 Python 语法:

command = "ffmpeg -i "concat:1.ts|2.ts" -vcodec copy -acodec copy temp.mp4"

如果你的 Python 文件中只有这一行,你会得到一个语法错误。用双引号括起来的字符串文字中不能有双引号,除非它们用反斜杠转义。因此,您可以通过将其替换为来修复该行:

command = "ffmpeg -i \"concat:1.ts|2.ts\" -vcodec copy -acodec copy temp.mp4"

解决这一行的另一种方法是在 Python 中对字符串文字使用单引号,这样当字符串本身包含双引号时 Python 就不会混淆:

command = 'ffmpeg -i "concat:1.ts|2.ts" -vcodec copy -acodec copy temp.mp4'

修复语法错误后,您可以使用subprocess 解决该问题,如this answer 中所述。我还写了this answer to explain a helpful mental model for subprocess in general。

【讨论】:

【参考方案2】:

任何遭受这种痛苦的人。它也适用于用引号括起来的参数。

params = ["ls", "-la"]
subprocess.check_output(" ".join(params), shell=True)

【讨论】:

【参考方案3】:

我一直在处理类似的问题,运行一个相对复杂的 通过 ssh 命令。它也有多个双引号和单引号。因为 我正在通过pythonsshpowershell 等传递命令。

如果您可以将命令转换为 shell 脚本,然后运行 shell脚本通过subprocess.call/Popen/run,这些问题就会消失。

因此,根据您使用的是 windows 还是 linux 或 mac,请将 在 shell 脚本中跟随(script.shscript.bat

ffmpeg -i "concat:1.ts|2.ts" -vcodec copy -acodec copy temp.mp4

然后就可以运行了

import subprocess; subprocess.call(`./script.sh`; shell=True)

无需担心单引号等

【讨论】:

使用 Popen 将参数发送到 shell 脚本也可能会有所帮助,例如:subprocess.Popen(["./cheddar.sh", "17"], stdout=subprocess.PIPE)。这会将数字 17 作为第一个参数发送到 cheddar.sh 脚本。请注意,shell 脚本中的参数可以作为 $1、$2、$3、... $n 访问。因此,在本例中,您可以将数字 17 获取为 $1。【参考方案4】:

还在处理包含空格且不想使用 shell=True 的字符串参数。

解决方案是对内部字符串使用双引号。

args = ['salt', '-G', 'environment:DEV', 'grains.setvals', '"man_version": "man-dev-2.3"']

try:
    p = subprocess.Popen(args, stdin=subprocess.PIPE
                             , stdout=subprocess.PIPE
                             , stderr=subprocess.PIPE
                        )
    (stdin,stderr) = p.communicate()
except (subprocess.CalledProcessError, OSError ) as err:
    exit(1)
if p.returncode != 0:
    print("Failure in returncode of command:")

【讨论】:

有什么理由使用双引号吗?据我了解,Python 中的单引号和双引号没有区别——只有当你想将一个组放在另一个组中时。但这个答案已经存在。【参考方案5】:

使用单引号'around the "whole pattern"' 自动转义双精度或显式"escape the \"double quotes\""。您的问题与Popen 本身无关。

为了记录,我遇到了一个问题,特别是传递给Popen 的基于list 的命令不会在全局模式周围保留正确的双引号(即在Windows 下的accepted answer)。在将列表传递给Popen 之前,将列表加入到带有' '.join(cmd) 的字符串中解决了这个问题。

【讨论】:

这是对我有用的答案。我必须做subprocess.run(" ".join(cmd), shell=True) 才能让它工作。没有其他工作。 我使用相同的方法将非代理主机 (-N) 传递给 JMeter "*.local|localhost"。我正在使用 python 向用户请求代理密码。【参考方案6】:

这适用于 python 2.7.3 管道 stderr 到 stdout 的命令已更改,因为旧版本的 python:

把它放在一个名为 test.py 的文件中:

#!/usr/bin/python
import subprocess

command = 'php -r "echo gethostname();"'
p = subprocess.Popen(command, universal_newlines=True, shell=True, 
stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
text = p.stdout.read()
retcode = p.wait()
print text

调用它:

python test.py

它会打印我的主机名,即 apollo:

apollo

阅读子流程手册:http://docs.python.org/2/library/subprocess.html

【讨论】:

【参考方案7】:

我建议使用列表形式的调用而不是引用的字符串版本:

command = ["ffmpeg", "-i", "concat:1.ts|2.ts", "-vcodec", "copy",
           "-acodec", "copy", "temp.mp4"]
output,error  = subprocess.Popen(
                    command, universal_newlines=True,
                    stdout=subprocess.PIPE, stderr=subprocess.PIPE).communicate()

这更准确地表示了将要传递给最终进程的确切参数集,并且无需弄乱 shell 引用。

也就是说,如果您绝对想使用纯字符串版本,只需使用不同的引号(和shell=True):

command = 'ffmpeg -i "concat:1.ts|2.ts" -vcodec copy -acodec copy temp.mp4'
output,error  = subprocess.Popen(
                    command, universal_newlines=True, shell=True,
                    stdout=subprocess.PIPE, stderr=subprocess.PIPE).communicate()

【讨论】:

在 Unix 上(至少),如果你要传递一个字符串,你需要使用 shell=True。否则,据我了解,python 将在您的路径中查找名为 ffmpeg -i "concat.... 的程序——该程序将不存在。 感谢您花时间回答,不幸的是,实际的 ffmpeg 命令需要文字引号传递 concat:file1|file2 参数,所以我正在寻找一种方法将文字引号从 python 子进程传递给 ffmpeg。弹出命令 @FightFireWithFire 最后一个版本不适合你吗?我相信它可以满足您的需求。 在第一个版本中使用'"concat:1.ts|2.ts"' @FightFireWithFire:如果您需要两种引号,那么您可以使用三引号 Python 文字:`cmd = r"""cmd "concat:1.ts|2.ts" $' \t' ..."""

以上是关于将python中的双引号shell命令传递给subprocess.Popen()?的主要内容,如果未能解决你的问题,请参考以下文章

shell中的   中文和英文   双引号

linux shell脚本,怎样变量传递执行结果

当 args 包含单引号和双引号时,如何将命令 args 传递给 python 脚本?

将单引号和双引号传递给python脚本

如何在bash脚本中传递变量的双引号值作为curl命令的参数?

为啥 shell 忽略通过变量传递给它的参数中的引号字符? [复制]