最近遇到的一个问题:在程序中有一个文件名,需要生成并执行一个 shell 命令,比如通过 os.execute 执行。但这个文件名可能包含特殊字符。
比如,如果文件名是:这个文件名不能直接在 shell 命令中使用
[SumiSora&CASO&HKG][Tears_to_Tiara][02][GB].rmvb
那么转义之后就是:
\[SumiSora\&CASO\&HKG\]\[Tears_to_Tiara\]\[02\]\[GB\].rmvb
或者采用单引号的办法:
'[SumiSora&CASO&HKG][Tears_to_Tiara][02][GB].rmvb'
经过一些搜索:
http://stackoverflow.com/questions/35817/how-to-escape-os-system-calls-in-python
http://stackoverflow.com/questions/5608112/escape-filenames-using-the-same-way-bash-do-it
我找到了 bash 的内置命令 printf "%q" str 可以实现这个功能,于是下载了 bash 的源代码来看。首先定位到 builtins/printf.def 文件,其中 q 的部分调用了以下函数:
ansic_shouldquote
ansic_quote
sh_backslash_quote
前两个函数在 lib/sh/strtrans.c 中,后一个函数在 lib/sh/shquote.c 中。所以最后终于定位到 shquote.c 这个文件。
1. 如果要使用单引号转义,那么使用 sh_single_quote 的算法
2. 想用反斜线转义,使用 sh_blackslash_quote 的算法
## 实现
出于方便考虑,我只实现了单引号转义,下面是一个 lua 的实现
function shquote(s)
return "."..string.gsub("'", "'\''").."'"
end