在emacs lisp中将多个path组件连接成一个完整path的正确方法是什么?

假设我有variablesdirfile包含string代表一个目录和文件名,分别。 emacs lisp将文件join文件的完整path的正确方法是什么?

例如,如果dir"/usr/bin"file"ls" ,那么我想要"/usr/bin/ls" 。 但是如果dir"/usr/bin/" ,我仍然想要同样的东西,没有重复的斜杠。

阅读目录名称手册,你会发现答案:

给定一个目录名称,您可以使用concat将其与相对文件名称结合使用:

  (concat dirname relfile) 

在做之前一定要确认文件名是相对的。 如果使用绝对文件名,则结果可能在语法上无效或引用错误的文件。

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

  (concat (file-name-as-directory dirfile) relfile) 

不要像手中那样手动连接斜线

  ;;; Wrong! (concat dirfile "/" relfile) 

因为这不是便携式的。 始终使用file-name-as-directory

其他有用的命令是: file-name-directoryfile-name-nondirectory file-name-directory以及文件名称组件部分中的其他命令。

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

 (expand-file-name "ls" "/usr/bin") "/usr/bin/ls" (expand-file-name "ls" "/usr/bin/") "/usr/bin/ls" 

编辑:这只适用于绝对目录名称。 我认为Trey的回答是最好的解决办法。

我想要将多个嵌套目录join到path中。 最初我使用了多个expand-file-name调用,如下所示:

 (expand-file-name "b" (expand-file-name "a" "/tmp")) "/tmp/a/b" 

但是,这是相当详细的,并反向读取。

相反,我写了一个像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)))) 

它的工作原理如下:

 (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" 

如果使用方便的文件和目录操作库f.el ,则只需要f-join 。 下面的代码是为那些由于某种原因拒绝使用这个库。

 (defun os-path-join (a &rest ps) (let ((path a)) (while ps (let ((p (pop ps))) (cond ((string-prefix-p "/" p) (setq path p)) ((or (not path) (string-suffix-p "/" p)) (setq path (concat path p))) (t (setq path (concat path "/" p)))))) path)) 

这与Python的os.path.join完全相同。

 ELISP> (os-path-join "~" "a" "b" "") "~/a/b/" ELISP> (os-path-join "~" "a" "/b" "c") "/b/c" 

string-suffix-p 在Emacs 24.4之前不存在,所以我写了自己的检查string是否以Emacs Lisp后缀结尾 。

以下是我使用的:

 (defun catdir (root &rest dirs) (apply 'concat (mapcar (lambda (name) (file-name-as-directory name)) (push root dirs)))) 

与@ dbr's的区别:

  1. 返回“emacs目录名称”,即带有斜线的值
  2. 如果root是相对的,它不会扩展path(请参阅注释)
  3. root为根,而joindirs将以"/"开始的第一个组件作为根。

笔记

许多文件处理函数(大多数,???)将标准化冗余斜线,并在相对path上调用expand-file-name (或类似),所以#2和#3可能无关紧要。