Python 在subprocess.Popen中使用通配符

Python 在subprocess.Popen中使用通配符,python,raspberry-pi,subprocess,wildcard,Python,Raspberry Pi,Subprocess,Wildcard,我已经找到了一些解决通过Popen传递通配符问题的答案,但我似乎无法让这些解决方案在我的特定情况下发挥作用 我有一个项目,按下按钮时将合并音频和视频文件,我需要使用subprocess.Popen执行我想要的命令: mergeFile = "ffmpeg -i /home/pi/Video/* -i /home/pi/Audio/test.wav -acodec copy -vcodec copymap 0:v -map 1:a /home/pi/Test/output.mkv" proc= s

我已经找到了一些解决通过Popen传递通配符问题的答案,但我似乎无法让这些解决方案在我的特定情况下发挥作用

我有一个项目,按下按钮时将合并音频和视频文件,我需要使用subprocess.Popen执行我想要的命令:

mergeFile = "ffmpeg -i /home/pi/Video/* -i /home/pi/Audio/test.wav -acodec copy -vcodec copymap 0:v -map 1:a /home/pi/Test/output.mkv"
proc= subprocess.Popen(shlex.split(mergeFiles), shell=True)
我基本上想把我的视频文件夹中的任何文件(我的项目从相机下载视频,每次保存新视频时文件名都会更改)合并到单独的“音频”文件夹中的音频,然后将该文件保存到另一个文件夹中

我试着将shell设置为true,但没有任何效果


我也不知道glob模块在这种情况下会如何帮助我。

这里的问题是
shlex.split()
。当与
shell=True
结合使用时,这意味着只有字符串
ffmpeg
被视为脚本,并且命令行的其他组件作为参数传递给该脚本(它从不查看/读取)


更好的做法是仍然使用
shell=True
(如果您实际正在参数化目录名和文件名),可能是:

mergeFile=[
    'ffmpeg -i "$1"/* -i "$2" -acodec copy -vcodec copymap 0:v -map 1:a "$3"',
    '_',                          # placeholder for $0
    "/home/pi/Video",             # directory for $1 -- can use a variable here
    "/home/pi/Audio/test.wav",
    "/home/pi/Test/output.mkv",
]
subprocess.Popen(mergeFile, shell=True)
…在这种情况下,脚本本身是常量(不能通过文件名或其他参数注入的值来更改其含义),但可以提供带外数据


比这更好的是完全停止使用
shell=True
。考虑:

import subprocess, glob

mergeFile=[
  'ffmpeg', '-i',
] + (glob.glob('/home/pi/Video/*') or ['/home/pi/Video/*']) + [
  '-i', '/home/pi/Audio/test.wav',
  '-acodec', 'copy',
  '-vcodec', 'copymap', '0:v',
  '-map', '1:a1',
  '/home/pi/Test/output.mkv' 
]
subprocess.Popen(mergefile)

存在
或['/home/pi/Video/*']
时,如果不存在与glob匹配的文件,则会产生与shell相同的错误消息。显然,在这种情况下也可以中止。

取出
shlex.split()
。只需传递字符串本身即可。将
shlex.split()
subprocess.Popen()
结合使用是一个常见的习惯用法(使用
shell=False
)——这是一个非常不幸的习惯用法,IMHO。使用
shell=False
的全部目的是允许传递一个明确的、明确的参数列表(正好包含您想要的文件名和其他参数)——当您开始将参数列表形成一个字符串,然后让库解析该字符串时,你突然增加了模糊性,你可以选择没有……而且,很清楚,
shell=True
是模糊的,容易出现安全漏洞,或者是一个坏主意。考虑一下,如果不是硬编码一个文件名在你的代码> MiGeFrase字符串中,你就从上传目录中获得了<代码>操作系统.ListDIR()/<代码>——除非你小心地创建了那个字符串,一个用<代码>触摸$$(RM -Rf)\ $(RM -Rf)创建的文件。\“.wav可能会产生非常不幸的副作用。
shlex.split()
是抵御shell注入攻击的第一道防线,我认为这就是为什么它可以优于
shell=True
。它不能捕获所有内容,最终可能会将shell元字符作为参数传递给混淆的结果,但它仍然优于替代方法。@tdelaney,“替代方法”(至少在最佳可用替代方法的意义上)不是
shell=True
——替代方法是传递一个显式argv数组
shell=False
with
shlex.split()
确实将您从
$(…)
中保存,但对于名为
foo的文件--execute trigger command=…
没有帮助;将所有参数传递到带外(即使使用
shell=True
,就像
[“脚本在此处使用“$1”和“$2”,“'''u',参数1,参数2]
)一样)是正确的;任何不足之处都是一种折衷。(当然,
--execute trigger command=
有点做作,但对于我们当前的ffmpeg,有许多选项/命令可用于使用当前用户的代理凭据SSH到资源;从本地网络检索内容;或以其他方式制造麻烦——请参阅)。
import subprocess, glob

mergeFile=[
  'ffmpeg', '-i',
] + (glob.glob('/home/pi/Video/*') or ['/home/pi/Video/*']) + [
  '-i', '/home/pi/Audio/test.wav',
  '-acodec', 'copy',
  '-vcodec', 'copymap', '0:v',
  '-map', '1:a1',
  '/home/pi/Test/output.mkv' 
]
subprocess.Popen(mergefile)