最近遇到的一個問題:在程式中有一個檔案名稱,需要產生並執行一個 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