FFmpeg单引号转义失效:含单引号文件名无法批量转换
解决FFmpeg批量转换脚本中含单引号文件名的问题
你的问题出在用shell=True执行命令时的单引号转义逻辑——shell的单引号是强引用,内部的所有字符(包括反斜杠)都会原样解析,所以你之前的转义方法根本无效,要么触发shell语法错误,要么转义字符被当成文件名的一部分。
直接用下面的修复脚本,彻底避开shell解析的坑:
import os import subprocess from multiprocessing.pool import ThreadPool as Pool source_dir = "/home/kris/Music/test" output_dir = "/home/kris/Music/test_opus" # 确保输出目录存在,避免FFmpeg因目录不存在报错 os.makedirs(output_dir, exist_ok=True) def worker(file): try: # 跳过非flac格式的文件 if not file.lower().endswith('.flac'): return # 用os.path.join拼接路径,自动处理不同系统的路径分隔符和特殊字符 input_path = os.path.join(source_dir, file) # 用os.path.splitext提取文件名,比手动拆分后缀更可靠 filename = os.path.splitext(file)[0] output_path = os.path.join(output_dir, f"{filename}.opus") # 用列表传递命令参数,不需要任何手动转义 cmd = [ "ffmpeg", "-n", "-i", input_path, "-c:a", "libopus", "-b:a", "320k", output_path ] # 执行命令,去掉shell=True,直接传递参数列表 result = subprocess.call(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE) if result != 0: print(f"处理失败: {file}") except Exception as e: print(f"处理出错: {file} - {str(e)}") def start(): threads = os.cpu_count() or 4 pool = Pool(threads) files = os.listdir(source_dir) for item in files: pool.apply_async(worker, (item,)) pool.close() pool.join() start()
关键修改点说明
- 去掉
shell=True,改用列表传参:subprocess会直接把每个列表元素作为独立参数传给FFmpeg,完全绕过shell的解析逻辑,任何特殊字符(单引号、空格、中文等)都能被正确处理,不需要手动转义。 - 用
os.path.join拼接路径:避免手动拼接路径时的分隔符问题,同时自动兼容不同系统的路径规则。 - 用
os.path.splitext提取文件名:比手动拆分.flac更通用,能处理大写后缀(如.FLAC)的文件。 - 添加输出目录创建逻辑:提前确保输出目录存在,避免FFmpeg因目录不存在抛出错误。
- 完善错误反馈:捕获具体异常并打印,方便排查单文件处理失败的原因。
测试验证
用文件名I'm a file.flac测试时,脚本会直接把完整路径传给FFmpeg,不会出现任何转义问题,FFmpeg能正确识别文件并完成转换。
内容的提问来源于stack exchange,提问作者XorOrNor
相关产品推荐
相关产品推荐

