Ehv*_*nce 5 common-lisp pathname home-directory
我有一个带有波浪号的目录名称(作为字符串):~/projects。
我想获取它的完整路径:/home/user/projects。我怎么做 ?
目标是将其传递给uiop:run-program,这似乎没有做正确的事情\xc2\xa9。
有了这个答案:如何将 (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/"\nRun Code Online (Sandbox Code Playgroud)\n\n=> 错误
\n\n谢谢。
\n\n编辑我将分享更多背景信息。
\n\n我想通过运行一个程序uiop:launch-program。我有一个用户定义的目录列表,例如~/projects. 使用它来创建./~/projects目录而不是/home/user/projects.
truename如果目录不存在则不起作用。
在 SBCL 上,(namestring "~/doesntexist")还返回其波形符。
merge-pathnames没用,仍然是波浪号问题。
使用ensure-directories-exist此结果创建了一个名为 的目录~。
给出答案后,我别无选择,只能调整逻辑来扩展我们实际想要存在的目录的目录名称。
\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)\nRun Code Online (Sandbox Code Playgroud)\n\n然后我就可以使用它了truename。
您的 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获取灵感。
小智 3
uiop 中有一个 native-namestring 函数,它应该在所有实现中都可用:
(uiop:native-namestring "~/projects")
=> /home/user/projects
Run Code Online (Sandbox Code Playgroud)