You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在Python中无引号正确转义Linux路径?

问题

网上关于Unix路径转义的大量回答要么完全错误,要么仅在小范围内适用,未考虑全面情况。我需要将含空格的路径(示例:/home/user/text/Chapter 1-100)转换为单个反斜杠转义空格的格式(即/home/user/text/Chapter\ 1-100),该格式用于生成ffmpeg批量合并音频的concat文件——ffmpeg仅接受这种字面转义格式,不支持带引号的字符串、双反斜杠等写法。

但在Python中尝试多种方法均失败:

  • shlex.quote仅给字符串添加引号,不符合要求
  • replace(' ', r'\ ')仅能处理空格,且若路径含其他特殊字符(如&、*)会失效
  • os.normpath无法生成所需的转义格式

我编写了一个音频书合并脚本,用natsort排序wav文件并按每5个一组生成concat文本文件,但路径转义问题导致ffmpeg无法识别路径。附脚本代码:

#!/bin/env python3
import os
import sys
import glob
import re
import ffmpeg
from rich import print
from natsort import natsorted
import shutil
import shlex


def natsorter(list, path):
    files = glob.glob(f"{path}/*.wav")
    files = natsorted(files)
    return files


# def sorted_alphanumeric(data):
# convert = lambda text: int(text) if text.isdigit() else text.lower()
# alphanum_key = lambda key: [ convert(c) for c in re.split('([0-9]+)', key) ]
# return sorted(data, key=alphanum_key)

# this is where I start sorting wav files
# add fils to a list, sort list and create a new list
# that are lists of 5 audio files ie 1-5, 6-10 etc...
newlist = []
path = os.getcwd()
files = glob.glob(f"{path}/*.wav")
# send list of files and path of files to sort them numerically in order
# this is important for an audiobook
newlist = natsorter(files, path)

# create empty slices array
slices = []


# function to slice an array into chunks of {n}
def divide_chunks(l, n):
    # Looping until length 1
    # start at 0 (first), to the full length, n is the step
    for i in range(0, len(l), n):
        # yield is like return it creates a list object and appends stuff to it
        yield l[i : i + n]
        slices.append(l[i : i + n])


# n is the number of files to slice together in ffmpeg file
# ie "file path/to/file.wav"
n = 5
x = list(divide_chunks(newlist, n))
print("--------------------")
print("SLICES YIELD: ")
print(x)
print("--------------------")


# create concat text files for ffmpeg
def concat_list():
    # files_concat = []
    i = 1
    total = 0
    for arrays in slices:
        total += len(arrays)
        name = f"{i}-{total}.txt"
        i += len(arrays)
        file = open(name, "w")
        for items in arrays:
            items = os.path.abspath(items).replace(" ", r"\ ")
            file.write("file " + items + "\n")
        file.close()
        # files_concat.append(name) -> switched to yield :) i learned a thing
        yield name


catfiles = list(concat_list())
# catfiles = []
print(catfiles)
for x in catfiles:
    ffmpeg.input(x, f="concat", safe=0).output(
        f"{x}.wav", codec="copy"
    ).overwrite_output().run()
    catfiles.append(f"{x}.wav")

解决方案

方法1:纯Python实现Unix风格路径转义

编写一个转义函数,对所有Unix shell中需要转义的字符(空格、!、#、$、&、'、(、)、*、?、[、]、{、}、\、;、<、>、|、~等)添加单个反斜杠,完全模拟printf '%q'的效果:

def escape_unix_path(path):
    # 需要转义的特殊字符集合
    special_chars = set(r' !#$&\'()*?[]{};><|~')
    escaped = []
    for char in path:
        if char in special_chars:
            escaped.append('\\' + char)
        else:
            escaped.append(char)
    return ''.join(escaped)

方法2:调用系统printf命令(依赖Unix环境)

直接调用bash的printf '%q'命令来生成转义路径,效果最准确:

import subprocess

def escape_unix_path(path):
    result = subprocess.run(
        ['printf', '%q', path],
        capture_output=True,
        text=True
    )
    return result.stdout

修改你的脚本

将concat_list函数中的路径处理部分替换为上述转义函数即可:

# 先定义escape_unix_path函数(二选一)
def escape_unix_path(path):
    special_chars = set(r' !#$&\'()*?[]{};><|~')
    escaped = []
    for char in path:
        if char in special_chars:
            escaped.append('\\' + char)
        else:
            escaped.append(char)
    return ''.join(escaped)

# 修改concat_list函数
def concat_list():
    i = 1
    total = 0
    for arrays in slices:
        total += len(arrays)
        name = f"{i}-{total}.txt"
        i += len(arrays)
        with open(name, "w") as file:  # 改用with语句更安全
            for items in arrays:
                abs_path = os.path.abspath(items)
                escaped_path = escape_unix_path(abs_path)
                file.write(f"file {escaped_path}\n")
        yield name

这样生成的concat文件中,路径会以file /home/user/text/Chapter\ 1-100/file.wav的格式写入,完全符合ffmpeg的要求。

内容的提问来源于stack exchange,提问作者sweet

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.22 17:03:10