将带有波形符的文件名展开为其完整路径 (Common Lisp)

Ehv*_*nce 5 common-lisp pathname home-directory

我有一个带有波浪号的目录名称(作为字符串):~/projects

\n\n

我想获取它的完整路径:/home/user/projects。我怎么做 ?

\n\n

目标是将其传递给uiop:run-program,这似乎没有做正确的事情\xc2\xa9。

\n\n
\n\n

有了这个答案:如何将 (make-pathname :directory '(:absolute :home "directoryiwant") 翻译成绝对路径

\n\n
(merge-pathnames \n          (make-pathname\n           :directory \'(:relative "~/projects"))\n          (user-homedir-pathname))\n#P"/home/me/~/projects/"\n
Run Code Online (Sandbox Code Playgroud)\n\n

=> 错误

\n\n

谢谢。

\n\n
\n\n

编辑我将分享更多背景信息。

\n\n

我想通过运行一个程序uiop:launch-program。我有一个用户定义的目录列表,例如~/projects. 使用它来创建./~/projects目录而不是/home/user/projects.

\n\n

truename如果目录不存在则不起作用。

\n\n

在 SBCL 上,(namestring "~/doesntexist")还返回其波形符。

\n\n

merge-pathnames没用,仍然是波浪号问题。

\n\n

使用ensure-directories-exist此结果创建了一个名为 的目录~

\n\n

给出答案后,我别无选择,只能调整逻辑来扩展我们实际想要存在的目录的目录名称。

\n\n
;; Create a directory\n;; Ensure its name (string) ends with a slash.\n(setf mydir\n        (str:concat (string-right-trim (list #\\/) mydir)\n                    "/"))\n(ensure-directories-exist base)\n
Run Code Online (Sandbox Code Playgroud)\n\n

然后我就可以使用它了truename

\n

cor*_*ump 6

一般评论~

您的 Lisp 实现可能支持也可能不支持波浪线语法。

如果是这样(例如 CCL、ABCL、CLISP、ECL、LispWorks),则将truename始终扩展为文件名:

(truename "~/projects")
 => /home/user/projects
Run Code Online (Sandbox Code Playgroud)

如果您的实现没有,或者如果您想要可移植地编码,则必须相对合并(user-homedir-pathname)

(truename (merge-pathnames #p"projects" (user-homedir-pathname)))
 => /home/user/projects
Run Code Online (Sandbox Code Playgroud)

请注意,波浪号(如果支持)似乎仅支持用作路径名的字符串,而不支持目录组件;(:relative "~")并不像你期望的那样工作,而是引用一个字面名为“~”的目录。

相反,至少对于 SBCL,适当的目录是(:absolute :home),或者,如果您想引用另一个用户,您可以将该组件包装在列表中:

(make-pathname :directory '(:absolute (:home "root")))
=> #P"~root/"
Run Code Online (Sandbox Code Playgroud)

请注意,只有当:home表单紧接在 后面时它才起作用:absolute,否则它不起作用(请参阅主目录说明符)。

扩展到不存在的路径名

truename会要求该事物存在吗?

是的,如果您想构建(尚)不存在的文件的绝对路径,那么您需要调用truename存在的部分,并与其合并。在你的情况下,那就是(truename "~/"),它与 相同(user-homedir-pathname)

正如 Rainer Joswig 所指出的,调用namestringSBCL 以外的实现会返回扩展的路径名,翻译~/home/user. 在 SBCL 中,您必须调用sb-ext:native-namestring才能获得相同的效果。

换句话说,为了扩展到不一定存在的文件名,您可以编写以下可移植层:

(defun expand-file-name (pathname)
  (check-type pathname pathname)
  (block nil
    #+(or lispworks clozure cmu clisp ccl armedbear ecl)
    (return (namestring pathname))
    #+sbcl
    (return (native-namestring pathname))
    #+(not (or sbcl lispworks clozure cmu clisp ccl armedbear ecl))
    (let ((expanded (namestring pathname)))
      (prog1 expanded
        (assert (not find #\~ expanded) () 
                 "Tilde not supported")))))
Run Code Online (Sandbox Code Playgroud)

如果您的 Lisp 不支持该语法,另请参阅https://github.com/xach/tilde/blob/master/tilde.lisp获取灵感。

  • `namestring` 可以在许多理解 `~` 的实现中工作:CCL、ABCL、CLISP、ECL、LispWorks。SBCL 返回波形符名称... (2认同)

小智 3

uiop 中有一个 native-namestring 函数,它应该在所有实现中都可用:

(uiop:native-namestring "~/projects")
=> /home/user/projects
Run Code Online (Sandbox Code Playgroud)