41.2 Shell 参数

Lisp 程序有时需要运行 Shell 并向其传递包含用户指定文件名的命令。这些程序应能支持所有合法文件名。但 Shell 会对某些字符特殊处理,若文件名中出现这些字符,会使 Shell 产生混淆。要处理这些字符,可使用函数 shell-quote-argument

Function: shell-quote-argument argument &optional posix

此函数返回一个字符串,以 Shell 语法表示内容为 argument 的参数。将返回值拼接进 Shell 命令并传递给 Shell 执行时应能可靠工作。

该函数的具体行为取决于操作系统。函数设计为适配系统标准 Shell 的语法;若使用非常规 Shell,则需要重新定义此函数。See 安全注意事项

;; 本例展示 GNU 与类 Unix 系统上的行为。
(shell-quote-argument "foo > bar")
     ⇒ "foo\\ \\>\\ bar"

;; 本例展示 MS-DOS 与 MS-Windows 上的行为。
(shell-quote-argument "foo > bar")
     ⇒ "\"foo > bar\""

以下是使用 shell-quote-argument 构造 Shell 命令的示例:

(concat "diff -u "
        (shell-quote-argument oldfile)
        " "
        (shell-quote-argument newfile))

若可选参数 posixnil,则无论系统 Shell 如何,均按照 POSIX Shell 转义规则对 argument 转义。当 Shell 可能运行在远程主机上时很有用,这类场景通常需要 POSIX Shell。

(shell-quote-argument "foo > bar" (file-remote-p default-directory))

以下两个函数可用于将单个命令行参数字符串列表合并为单个字符串,或将字符串拆分为单个命令行参数列表。这些函数主要用于将小缓冲区中的用户输入(Lisp 字符串)转换为字符串参数列表,传递给 make-processcall-processstart-process;或将此类参数列表转换为单个 Lisp 字符串,显示在小缓冲区或回显区。注意,若涉及 Shell(例如使用 call-process-shell-command),参数仍需通过 shell-quote-argument 保护;combine-and-quote-strings 并非用于保护特殊字符不被 Shell 解析。

Function: split-string-shell-command string

此函数将 string 拆分为子字符串,遵守双引号、单引号以及反斜杠转义规则。

(split-string-shell-command "ls /tmp/'foo bar'")
     ⇒ ("ls" "/tmp/foo bar")
Function: split-string-and-unquote string &optional separators

此函数按照正则表达式 separators 的匹配位置将 string 拆分为子字符串,与 split-string 类似(see 创建字符串);此外还会移除子字符串中的转义。随后将子字符串组成列表并返回。

separators 省略或为 nil,默认值为 "\\s-+",该正则表达式匹配一个或多个空白语法字符(see 语法类别表)。

此函数支持两种转义方式:用双引号 "…" 包裹整个字符串,以及用反斜杠转义 ‘\’ 单个字符。后者也用于 Lisp 字符串,因此该函数同样可以处理。

Function: combine-and-quote-strings list-of-strings &optional separator

此函数将 list-of-strings 拼接为单个字符串,按需对每个字符串转义。并在每对字符串之间插入 separator 字符串;若 separator 省略或为 nil,默认值为 " "。返回值为结果字符串。

list-of-strings 中需要转义的字符串是包含 separator 作为子串的字符串。转义时用双引号 "…" 包裹字符串。最简单的场景下,若从独立命令行参数构造命令,所有包含嵌入空格的参数都会被转义。