26.9.4 文件名展开相关函数

对文件名进行展开(expanding),是指将相对文件名转换为绝对文件名。 由于这一过程是相对于某个默认目录完成的, 你必须同时指定默认目录与待展开的文件名。 展开还包括对 ~/ 这类缩写的解析 (see abbreviate-file-name), 以及消除 ./name/../ 这类冗余路径。

Function: expand-file-name filename &optional directory

该函数将 filename 转换为绝对文件名。 若提供了 directory,则当 filename 为相对路径且不以 ‘~’ 开头时, 以此作为起始默认目录。 (directory 本身应为绝对目录名或目录文件名;可以 ‘~’ 开头。) 否则使用当前缓冲区的 default-directory。例如:

(expand-file-name "foo")
     ⇒ "/xcssun/users/rms/lewis/foo"
(expand-file-name "../foo")
     ⇒ "/xcssun/users/rms/foo"
(expand-file-name "foo" "/usr/spool/")
     ⇒ "/usr/spool/foo"

filename 中第一个斜杠前的部分为 ‘~’, 会被展开为你的主目录,通常由环境变量 HOME 指定 (see General Variables in The GNU Emacs Manual)。 若第一个斜杠前为 ‘~user’ 且 user 为有效登录名, 则展开为该用户的主目录。

如果你不希望对可能以字面量 ‘~’ 开头的相对文件名进行展开, 可以使用 (concat (file-name-as-directory directory) filename) 代替 (expand-file-name filename directory)

包含 ‘.’ 或 ‘..’ 的文件名会被简化为规范形式:

(expand-file-name "bar/../foo")
     ⇒ "/xcssun/users/rms/lewis/foo"

某些情况下,开头的 ‘..’ 组件可能会保留在结果中:

(expand-file-name "../home" "/")
     ⇒ "/../home"

这是为了兼容那些在根目录 / 之上还有超级根概念的文件系统。 在其他文件系统中,/..// 解析效果完全一致。

展开 . 或空字符串会返回默认目录:

(expand-file-name "." "/usr/spool/")
     ⇒ "/usr/spool"
(expand-file-name "" "/usr/spool/")
     ⇒ "/usr/spool"

注意:expand-file-name 不会 展开环境变量, 只有 substitute-in-file-name 会执行该操作:

(expand-file-name "$HOME/foo")
     ⇒ "/xcssun/users/rms/lewis/$HOME/foo"

另外,expand-file-name 在任何层级都不会跟随符号链接。 这导致 file-truenameexpand-file-name 对 ‘..’ 的处理方式存在差异。 假设 ‘/tmp/bar’ 是指向目录 ‘/tmp/foo/bar’ 的符号链接,则结果如下:

(file-truename "/tmp/bar/../myfile")
     ⇒ "/tmp/foo/myfile"
(expand-file-name "/tmp/bar/../myfile")
     ⇒ "/tmp/myfile"

如果你需要在 ‘..’ 之前跟随符号链接, 应确保直接调用 file-truename, 而不事先直接或间接调用 expand-file-name。See 真实路径

Variable: default-directory

这个缓冲区局部变量的值为当前缓冲区的默认目录。 它应为绝对目录名,可以 ‘~’ 开头。 该变量在每个缓冲区中都是局部有效的。

expand-file-name 的第二个参数为 nil 时, 会使用该默认目录。

其值始终是以斜杠结尾的字符串。

default-directory
     ⇒ "/user/lewis/manual/"
Function: substitute-in-file-name filename

该函数将 filename 中的环境变量引用替换为对应变量值。 遵循标准 Unix Shell 语法,‘$’ 为环境变量替换前缀。 若输入中包含 ‘$$’,会被转换为 ‘$’, 用户可通过这种方式对 ‘$’ 进行转义。

环境变量名是 ‘$’ 之后的一串字母、数字(包含下划线)。 若 ‘$’ 后紧跟 ‘{’, 则变量名为从该位置到匹配的 ‘}’ 之间的内容。

对已经经过 substitute-in-file-name 处理的结果 再次调用该函数,通常会产生错误。 例如,用于转义的 ‘$$’ 无法正常工作, 且环境变量值中的 ‘$’ 可能引发重复替换。 因此,若程序调用该函数后,输出会再次被传入本函数, 需要将所有 ‘$’ 加倍,以避免后续错误。

这里假设保存用户主目录的环境变量 HOME 值为 ‘/xcssun/users/rms’。

(substitute-in-file-name "$HOME/foo")
     ⇒ "/xcssun/users/rms/foo"

替换完成后,若 ‘~’ 或 ‘/’ 紧跟在另一个 ‘/’ 之后, 函数会丢弃其之前的所有内容(直到紧邻的前一个 ‘/’)。

(substitute-in-file-name "bar/~/foo")
     ⇒ "~/foo"
(substitute-in-file-name "/usr/local/$HOME/foo")
     ⇒ "/xcssun/users/rms/foo"
     ;; /usr/local/ has been discarded.

某些场景下并不希望展开文件名。 此时可以对文件名进行引用,阻止展开并按字面量处理。 引用方式为在文件名前添加前缀 ‘/:’。

Macro: file-name-quote name

该宏为文件名 name 添加引用前缀 ‘/:’。 对于本地文件名 name,直接在前方添加 ‘/:’。 若 name 为远程文件名,则对其本地部分(see 实现“魔法”文件名机制)进行引用。 若 name 已是被引用的文件名,则直接原样返回。

(substitute-in-file-name (file-name-quote "bar/~/foo"))
     ⇒ "/:bar/~/foo"

(substitute-in-file-name (file-name-quote "/ssh:host:bar/~/foo"))
     ⇒ "/ssh:host:/:bar/~/foo"

该宏无法用于阻止魔法文件名的文件名处理器生效(see 实现“魔法”文件名机制)。

Macro: file-name-unquote name

该宏从文件名 name 中移除引用前缀 ‘/:’(如果存在)。 若 name 为远程文件名,则对其本地部分取消引用。

Macro: file-name-quoted-p name

name 带有前缀 ‘/:’ 被引用,该宏返回非 nil。 若 name 为远程文件名,则检查其本地部分。


emacs

Emacs

org-mode

Orgmode

Donations

打赏

Copyright

© Jasper Hsu

Creative Commons

Creative Commons

Attribute

Attribute

Noncommercial

Noncommercial

Share Alike

Share Alike