将带有波浪号的文件名扩展为其完整路径(Common Lisp)
Expand a file name with a tilde to its fullpath (Common Lisp)
我有一个带波浪号的目录名(字符串形式):~/projects
.
我想获取它的完整路径:/home/user/projects
。我该怎么做?
目标是将其传递给 uiop:run-program
,这似乎不正确©。
有了这个答案:How to translate (make-pathname :directory '(:absolute :home "directoryiwant") into absolute path
(merge-pathnames
(make-pathname
:directory '(:relative "~/projects"))
(user-homedir-pathname))
#P"/home/me/~/projects/"
=> 错误
谢谢。
编辑我会分享更多内容。
我想通过 uiop:launch-program
运行 一个程序。我有一个用户定义的目录列表,例如 ~/projects
。使用它创建 ./~/projects
目录而不是 /home/user/projects
.
如果目录不存在,truename
不起作用。
在 SBCL 上,(namestring "~/doesntexist")
returns 也是波浪号。
merge-pathnames
没用,还是波浪号问题。
将此结果提供给 ensure-directories-exist
创建了一个名为 ~
.
的目录
鉴于答案,我别无选择,只能调整逻辑来扩展我们实际想要存在的目录的目录名称。
;; Create a directory
;; Ensure its name (string) ends with a slash.
(setf mydir
(str:concat (string-right-trim (list #\/) mydir)
"/"))
(ensure-directories-exist base)
然后我可以使用它 truename
。
关于 ~
的一般评论
您的 Lisp 实现可能支持也可能不支持波浪号语法。
如果是(例如 CCL、ABCL、CLISP、ECL、LispWorks),那么 truename
将始终扩展为文件名:
(truename "~/projects")
=> /home/user/projects
如果您的实现没有,或者如果您想编写可移植的代码,则必须相对于 (user-homedir-pathname)
:
进行合并
(truename (merge-pathnames #p"projects" (user-homedir-pathname)))
=> /home/user/projects
请注意,波浪号(如果支持的话)似乎只支持用作路径名的字符串,而不支持目录组件; (:relative "~")
没有像您预期的那样工作,而是引用了一个名为“~”的目录。
相反,至少对于 SBCL,合适的目录是 (:absolute :home)
,或者,如果你想引用另一个用户,你可以将组件包装在一个列表中:
(make-pathname :directory '(:absolute (:home "root")))
=> #P"~root/"
扩展到不存在的路径名
truename
would require that the thing exists?
是的,如果你想构建一个(还)不存在的文件的绝对路径,那么你需要在存在的部分上调用 truename
,并与之合并。
在您的情况下,这将是 (truename "~/")
,与 (user-homedir-pathname)
.
相同
正如 Rainer Joswig 所指出的,在 SBCL returns 以外的实现上调用 namestring
扩展路径名,将 ~
翻译为 /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")))))
如果您的 Lisp 不支持该语法,另请参阅 https://github.com/xach/tilde/blob/master/tilde.lisp 以获取灵感。
uiop中有一个native-namestring函数,应该在所有实现中都可用:
(uiop:native-namestring "~/projects")
=> /home/user/projects
Anselm Farber 的解决方案,涉及 uiop:native-namestring 在一些没有 native-namestrings 的路径名上中断,如下所示:
(uiop:native-namestring "~/Music/[Video] performance.mp4")
==>
The pathname #P"~/Music/[Video] performance.mp4"
does not have a native namestring because
of the :NAME component #<SB-IMPL::PATTERN (:CHARACTER-SET
. "Video")
" performance">.
[Condition of type SB-KERNEL:NO-NATIVE-NAMESTRING-ERROR]
这是一个只使用路径名函数的直接解决方案:
(defun expand-user-homedir (f)
(let ((d (pathname-directory f)))
(if (and (eql (car d) :absolute)
(eql (cadr d) :home))
(make-pathname :directory (append (pathname-directory (user-homedir-pathname))
(cddr d))
:name (pathname-name f)
:type (pathname-type f))
f)))
我有一个带波浪号的目录名(字符串形式):~/projects
.
我想获取它的完整路径:/home/user/projects
。我该怎么做?
目标是将其传递给 uiop:run-program
,这似乎不正确©。
有了这个答案:How to translate (make-pathname :directory '(:absolute :home "directoryiwant") into absolute path
(merge-pathnames
(make-pathname
:directory '(:relative "~/projects"))
(user-homedir-pathname))
#P"/home/me/~/projects/"
=> 错误
谢谢。
编辑我会分享更多内容。
我想通过 uiop:launch-program
运行 一个程序。我有一个用户定义的目录列表,例如 ~/projects
。使用它创建 ./~/projects
目录而不是 /home/user/projects
.
truename
不起作用。
在 SBCL 上,(namestring "~/doesntexist")
returns 也是波浪号。
merge-pathnames
没用,还是波浪号问题。
将此结果提供给 ensure-directories-exist
创建了一个名为 ~
.
鉴于答案,我别无选择,只能调整逻辑来扩展我们实际想要存在的目录的目录名称。
;; Create a directory
;; Ensure its name (string) ends with a slash.
(setf mydir
(str:concat (string-right-trim (list #\/) mydir)
"/"))
(ensure-directories-exist base)
然后我可以使用它 truename
。
关于 ~
的一般评论您的 Lisp 实现可能支持也可能不支持波浪号语法。
如果是(例如 CCL、ABCL、CLISP、ECL、LispWorks),那么 truename
将始终扩展为文件名:
(truename "~/projects")
=> /home/user/projects
如果您的实现没有,或者如果您想编写可移植的代码,则必须相对于 (user-homedir-pathname)
:
(truename (merge-pathnames #p"projects" (user-homedir-pathname)))
=> /home/user/projects
请注意,波浪号(如果支持的话)似乎只支持用作路径名的字符串,而不支持目录组件; (:relative "~")
没有像您预期的那样工作,而是引用了一个名为“~”的目录。
相反,至少对于 SBCL,合适的目录是 (:absolute :home)
,或者,如果你想引用另一个用户,你可以将组件包装在一个列表中:
(make-pathname :directory '(:absolute (:home "root")))
=> #P"~root/"
扩展到不存在的路径名
truename
would require that the thing exists?
是的,如果你想构建一个(还)不存在的文件的绝对路径,那么你需要在存在的部分上调用 truename
,并与之合并。
在您的情况下,这将是 (truename "~/")
,与 (user-homedir-pathname)
.
正如 Rainer Joswig 所指出的,在 SBCL returns 以外的实现上调用 namestring
扩展路径名,将 ~
翻译为 /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")))))
如果您的 Lisp 不支持该语法,另请参阅 https://github.com/xach/tilde/blob/master/tilde.lisp 以获取灵感。
uiop中有一个native-namestring函数,应该在所有实现中都可用:
(uiop:native-namestring "~/projects")
=> /home/user/projects
Anselm Farber 的解决方案,涉及 uiop:native-namestring 在一些没有 native-namestrings 的路径名上中断,如下所示:
(uiop:native-namestring "~/Music/[Video] performance.mp4")
==>
The pathname #P"~/Music/[Video] performance.mp4"
does not have a native namestring because
of the :NAME component #<SB-IMPL::PATTERN (:CHARACTER-SET
. "Video")
" performance">.
[Condition of type SB-KERNEL:NO-NATIVE-NAMESTRING-ERROR]
这是一个只使用路径名函数的直接解决方案:
(defun expand-user-homedir (f)
(let ((d (pathname-directory f)))
(if (and (eql (car d) :absolute)
(eql (cadr d) :home))
(make-pathname :directory (append (pathname-directory (user-homedir-pathname))
(cddr d))
:name (pathname-name f)
:type (pathname-type f))
f)))