如何正确传递子进程参数

2022-02-26 00:00:00 python subprocess ffmpeg concatenation

问题描述

我正在尝试自动连接MP4视频文件(格式正确)的文件夹。

(我的问题的这个编辑版本将问题减少到我的念力的最低级别。原标题询问了subprocess.callsubprocess.run之间的区别,但结果发现问题出在其他地方。)

为什么

subprocess.call('ffmpeg -hide_banner -loglevel error -i movie1.mp4 -i movie2.mp4 -i credits.mp4 
-filter_complex "[0:v:0] [0:a:0] [1:v:0] [1:a:0][2:v:0][2:a:0]concat=n=3:v=1:a=1[outv][outa]"  
-map "[outv]" -map "[outa]" "output.mp4"',shell=True)

工作正常(其中s为输入字符串,count为输入数),但

#python3 
#makeFinalExample.py

import subprocess

s = '-i movie1.mp4 -i movie2.mp4 -i credits.mp4'
count = 3
print(f's prints out as: {s}')


commandList = ['ffmpeg',
                '-hide_banner',
                '-loglevel',
                'error',
                #str(s),
                '{0}'.format(s),
                '-filter_complex',
                "[0:v:0][0:a:0][1:v:0][1:a:0]concat=n={0}:v=1:a=1[outv][outa]".format(count),
                '-map',
                "[outv]",
                '-map',
                "[outa]",
                "output.mp4"]
print(f'the command list prints out as {commandList}')
subprocess.run(commandList)

获取错误(字符串是以str(s)的形式传递,还是以显示的格式传递.

Unrecognized option 'i movie1.mp4 -i movie2.mp4 -i credits.mp4'.
Error splitting the argument list: Option not found

这里是输入字符串的打印输出

-i movie1.mp4 -i movie2.mp4 -i credits.mp4

这里是命令列表的打印输出

['ffmpeg', '-hide_banner', '-loglevel', 'error', '-i movie1.mp4 -i movie2.mp4 -i credits.mp4', '-filter_complex', '[0:v:0][0:a:0][1:v:0][1:a:0]concat=n=3:v=1:a=1[outv][outa]', '-map', '[outv]', '-map', '[outa]', 'output.mp4']

解决方案

这与subprocess.callvssubprocess.run无关,不同之处在于您在第一种情况下使用shell=True,而在第二种情况下不使用。这两个函数在这方面的行为完全相同,而且几乎所有其他方面都是如此(subprocess.run是一个较新的函数,它支持更多更多的选项,并返回更有用的对象,但在其最基本的形式中,它使用相同的API执行完全相同的工作)。

问题是您需要将字符串s拆分成标记,就像拆分所有其他命令行参数一样(错误消息实际上揭示了这一点,但我想您必须知道要查找什么才能捕获它)。当您省略shell=True时,每个选项都需要是单独的列表项,如

[ ..., '-i', 'movie1.mp4', '-i', 'movie2.mp4', '-i', 'credits.mp4', ...]

函数shlex.split()可以帮助您正确地将命令拆分成令牌:

commandList = [
    'ffmpeg',
    '-hide_banner',
    '-loglevel', 'error',
    *shlex.split(s),
    '-filter_complex',
    "[0:v:0][0:a:0][1:v:0][1:a:0]concat=n={0}:v=1:a=1[outv][outa]".format(count),
    '-map', "[outv]",
    '-map', "[outa]",
    "output.mp4"]

但是函数的一个更好的设计可能是允许用户只传入输入视频文件名的列表,然后从那里获取它。(那么我猜count也不需要显式指定;它只是len(inputfilenames)的值。)

相关文章