将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 命令。它也有多个双引号和单引号。因为
我正在通过python
、ssh
、powershell
等传递命令。
如果您可以将命令转换为 shell 脚本,然后运行
shell脚本通过subprocess.call/Popen/run
,这些问题就会消失。
因此,根据您使用的是 windows 还是 linux 或 mac,请将
在 shell 脚本中跟随(script.sh
或 script.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()?的主要内容,如果未能解决你的问题,请参考以下文章
当 args 包含单引号和双引号时,如何将命令 args 传递给 python 脚本?