在emacs lisp中将多个path组件连接成一个完整path的正确方法是什么?
假设我有variablesdir
和file
包含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-directory
, file-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的区别:
- 返回“emacs目录名称”,即带有斜线的值
- 如果
root
是相对的,它不会扩展path(请参阅注释) - 以
root
为根,而joindirs
将以"/"
开始的第一个组件作为根。
笔记
许多文件处理函数(大多数,???)将标准化冗余斜线,并在相对path上调用expand-file-name
(或类似),所以#2和#3可能无关紧要。