在emacs lisp中将多个路径组件连接到单个完整路径的正确方法是什么?

Rya*_*son 48 filenames elisp path-manipulation

假设我有变量dir并且分别file包含表示目录和文件名的字符串.emacs lisp将它们连接到文件的完整路径的正确方法是什么?

例如,如果dir"/usr/bin"file"ls"的话,我想"/usr/bin/ls".但是,如果不是dir就是"/usr/bin/",我还是希望同样的事情,没有重复的斜线.

Tre*_*son 61

阅读目录名称手册,您将找到答案:

给定目录名称,您可以使用以下命令将其与相对文件名组合 concat:

 (concat dirname relfile)
Run Code Online (Sandbox Code Playgroud)

在执行此操作之前,请务必验证文件名是否相对.如果使用绝对文件名,结果可能在语法上无效或引用错误的文件.

如果要在制作此类组合时使用目录文件名,则必须先使用以下命令将其转换为目录名file-name-as-directory:

 (concat (file-name-as-directory dirfile) relfile) 
Run Code Online (Sandbox Code Playgroud)

不要尝试用手连接斜线,如

 ;;; Wrong!
 (concat dirfile "/" relfile) 
Run Code Online (Sandbox Code Playgroud)

因为这不便携.一直用file-name-as-directory.

其他有用的命令是:file-name-directory,file-name-nondirectory和" 文件名组件"部分中的其他命令.

  • 呃,难怪我到处看到那些"连续",甚至我们的手册都鼓励这种用法.但是使用`expand-file-name`通常要好得多,除非你希望最终结果是相对文件. (5认同)

Hug*_*ugh 28

你可以使用expand-file-name这个:

(expand-file-name "ls" "/usr/bin")
"/usr/bin/ls"
(expand-file-name "ls" "/usr/bin/")
"/usr/bin/ls"
Run Code Online (Sandbox Code Playgroud)

编辑:这仅适用于绝对目录名称.我认为Trey的答案是更好的解决方案.


dbr*_*dbr 10

我想将多个嵌套目录连接到路径上.最初我使用过多次expand-file-name调用,如下所示:

(expand-file-name "b" (expand-file-name "a" "/tmp"))
"/tmp/a/b"
Run Code Online (Sandbox Code Playgroud)

然而,这是相当冗长的,并且向后读.

相反,我编写了一个像Python一样的函数os.path.join:

(defun joindirs (root &rest dirs)
  "Joins a series of directories together, like Python's os.path.join,
  (dotemacs-joindirs \"/tmp\" \"a\" \"b\" \"c\") => /tmp/a/b/c"

  (if (not dirs)
      root
    (apply 'joindirs
           (expand-file-name (car dirs) root)
           (cdr dirs))))
Run Code Online (Sandbox Code Playgroud)

它的工作原理如下:

(joindirs "/tmp" "a" "b")
"/tmp/a/b"
(joindirs "~" ".emacs.d" "src")
"/Users/dbr/.emacs.d/src"
(joindirs "~" ".emacs.d" "~tmp")
"/Users/dbr/.emacs.d/~tmp"
Run Code Online (Sandbox Code Playgroud)


jca*_*caw 7

这个问题是在 2010 年提出的,但在撰写本文时,它是“在 elisp 中加入文件路径”等搜索的热门话题,所以我想我会更新答案。

自 2010 年以来,Emacs 的世界发生了很大的变化。这有点重复,因为它在下面的答案被简要提及,但我会稍微充实一下。现在有一个用于文件交互的专用库f.el

受到@magnars出色的s.eldash.el 的启发f.el是一个现代 API,用于在 Emacs 中处理文件和目录。

不要试图重新发明轮子。您应该使用此库进行文件路径操作。你想要的功能是f-join

(f-join "path")                   ;; => "path"
(f-join "path" "to")              ;; => "path/to"
(f-join "/" "path" "to" "heaven") ;; => "/path/to/heaven"
Run Code Online (Sandbox Code Playgroud)

您可能需要先安装软件包。它应该在 MELPA 上可用。


Tsi*_*gyi 7

对于那些在 2021 年之后提出这个问题的人来说,elisp 内置函数file-name-concat可以完成这项工作。现在简单多了。

可以通过以下按键在 emacs 中找到文档:

C-h f file-name-concat <enter>

将 COMPONENTS 附加到 DIRECTORY 并返回结果字符串。

COMPONENTS 中的元素必须是字符串或 nil。DIRECTORY 或 COMPONENTS 中的非最终元素可能以斜杠结尾,也可能不以斜杠结尾——如果它们不以斜杠结尾,则在连接之前将插入斜杠。

其他相关函数记录在文件名组中。可能是在Emacs 28.1 版本
或之前引入的。 此函数不会更改全局状态,包括比赛数据。

(file-name-concat "/usr/bin/" "ls")
;; ==> "/usr/bin/ls"

(file-name-concat "/usr" "bin" "ls")
;; ==> "/usr/bin/ls"
Run Code Online (Sandbox Code Playgroud)