代码之家  ›  专栏  ›  技术社区  ›  Ryan C. Thompson

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

  •  46
  • Ryan C. Thompson  · 技术社区  · 15 年前

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

    例如,如果 董事 "/usr/bin" 文件 "ls" ,那么我想要 "/usr/bin/ls" . 但如果相反 董事 "/usr/bin/" ,我仍然想要同样的东西,没有重复的斜杠。

    5 回复  |  直到 15 年前
        1
  •  64
  •   anemator Trey Jackson    12 年前

    阅读手册 Directory Names

    给定目录名,可以组合 concat :

     (concat dirname relfile)
    

    确保文件名是 在那之前是相对的。如果你使用 一个绝对的文件名,结果 可能在语法上无效或 参考错误的文件。

    如果要使用目录文件 必须先将其转换为目录 使用名称 file-name-as-directory

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

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

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

    使用 文件名作为目录 .

    其他有用的命令包括: file-name-directory , file-name-nondirectory ,以及 File Name Components 章节。

        2
  •  28
  •   Hugh    15 年前

    你可以用 expand-file-name

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

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

        3
  •  10
  •   dbr    13 年前

    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"
    
        4
  •  3
  •   Community Mohan Dere    8 年前

    如果使用方便的文件和目录操作库 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))
    

    os.path.join .

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

    string-suffix-p 不存在 before Emacs 24.4 ,所以我在 Check if a string ends with a suffix in Emacs Lisp .

        5
  •  3
  •   sshaw    10 年前

    我用的是:

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

    1. 返回一个“emacs目录名”,即带有尾随斜杠的值
    2. 如果 root 是相对的(见注释)
    3. 对待 作为根,然而 joindirs 第一 组件以 "/"

    笔记

    许多文件处理功能(全部、大部分、全部)将规范化冗余斜杠并调用 expand-file-name

        6
  •  2
  •   JCC    6 年前

    这个问题是在2010年提出的,但在撰写本文的时候,它是像 “在elisp中连接文件路径” ,所以我想我会更新答案。

    自2010年以来,Emacs的世界发生了很多变化。这是一个有点重复的答案,因为它在一个答案中被简短地提到了 below ,但我会充实一下。现在有一个 dedicated library 对于文件交互, f.el :

    灵感来自 @magnars 太棒了 s.el dash.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"
    

    推荐文章