如何在Python脚本中执行含FFmpeg的复杂Shell命令?
在Python中执行带管道的FFmpeg命令并捕获输出
我来帮你搞定这个问题——要在Python里执行这条包含FFmpeg、grep和gawk的管道命令,并且实时捕获生成的分段文件名,其实有两种靠谱的实现方式,我给你详细说说:
方案一:直接用shell解析整个命令
如果你的命令是固定的,不用担心shell注入风险,直接把整个命令字符串传给subprocess并启用shell=True是最省事的方式:
import subprocess # 把你的完整命令直接写在这里 full_cmd = '''ffmpeg -i http://0.0.0.0:8080/stream/video.mjpeg -vcodec copy -map 0 -f segment -segment_time 2 -loglevel 40 -segment_format mp4 capture-%05d.mp4 2>&1 | grep --line-buffered -Eo "segment:.+ended" | gawk -F "'" '{print $2; system("")}' ''' # 启动进程,同时捕获stdout和stderr(因为FFmpeg日志输出到stderr) proc = subprocess.Popen( full_cmd, shell=True, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, text=True # 让输出以字符串形式返回,不用手动解码 ) # 实时逐行读取输出 for line in iter(proc.stdout.readline, ''): cleaned_line = line.strip() if cleaned_line: print(f"刚生成的分段文件:{cleaned_line}") # 这里可以加你自己的逻辑,比如把文件名存到列表、触发后续处理等 # 等待进程结束,获取返回码 proc.wait()
为什么这么写?
shell=True让系统shell帮你处理管道逻辑,不用自己拼接多个进程stderr=subprocess.STDOUT把FFmpeg的错误输出(也就是它的日志)重定向到stdout,这样我们只需要读一个流就行iter(proc.stdout.readline, '')用来实时读取输出,避免进程阻塞,确保每生成一个文件就能立刻拿到文件名
方案二:手动拼接管道(更安全)
如果担心shell注入风险,或者想更灵活地控制每个命令,可以把每个工具拆成独立的subprocess进程,手动连接它们的输入输出:
import subprocess # 1. 启动FFmpeg进程 ffmpeg_proc = subprocess.Popen( [ 'ffmpeg', '-i', 'http://0.0.0.0:8080/stream/video.mjpeg', '-vcodec', 'copy', '-map', '0', '-f', 'segment', '-segment_time', '2', '-loglevel', '40', '-segment_format', 'mp4', 'capture-%05d.mp4' ], stdout=subprocess.PIPE, stderr=subprocess.STDOUT, text=True ) # 2. 启动grep进程,把FFmpeg的输出作为grep的输入 grep_proc = subprocess.Popen( ['grep', '--line-buffered', '-Eo', 'segment:.+ended'], stdin=ffmpeg_proc.stdout, stdout=subprocess.PIPE, text=True ) # 关闭FFmpeg的stdout,这样当grep结束时FFmpeg会收到SIGPIPE信号终止 ffmpeg_proc.stdout.close() # 3. 启动gawk进程,把grep的输出作为gawk的输入 gawk_proc = subprocess.Popen( ['gawk', '-F', "'", '{print $2; system("")}'], stdin=grep_proc.stdout, stdout=subprocess.PIPE, text=True ) grep_proc.stdout.close() # 读取gawk的最终输出 for line in iter(gawk_proc.stdout.readline, ''): cleaned_line = line.strip() if cleaned_line: print(f"刚生成的分段文件:{cleaned_line}") # 等待所有进程结束 gawk_proc.wait() grep_proc.wait() ffmpeg_proc.wait()
关键注意点
- 一定要加
--line-buffered参数给grep和gawk,否则它们会用块缓冲模式,导致输出不会实时传递给Python,你要等很久才能拿到结果 system("")在gawk里是用来强制刷新输出缓冲的,这个不能省略,否则同样会出现输出延迟的问题- 如果你的系统里这些工具的路径不是全局可访问的,可以写绝对路径(比如
/usr/bin/ffmpeg)来避免找不到命令的问题
额外提醒
- 确保你的系统已经安装了ffmpeg、grep和gawk这三个工具
- 如果需要长时间运行脚本,建议加上异常处理(比如捕获
KeyboardInterrupt来优雅终止所有进程) - 测试的时候可以先把FFmpeg的输入换成本地视频文件,这样更容易调试
内容的提问来源于stack exchange,提问作者Rex Low
相关产品推荐
相关产品推荐

