Common lisp 将带有平铺的文件名扩展到其完整路径(Common Lisp)

Common lisp 将带有平铺的文件名扩展到其完整路径(Common Lisp),common-lisp,home-directory,pathname,Common Lisp,Home Directory,Pathname,我有一个带波浪号的目录名(字符串):~/projects 我想获得它的完整路径:/home/user/projects。我该怎么做 目标是将其传递给uiop:runprogram,这样做似乎不对 回答如下: =>错了 多谢各位 编辑我将分享更多内容 我想通过uiop:launch-program运行一个程序。我有一个用户定义的目录列表,比如~/projects。使用它创建/~/projects目录,而不是/home/user/projects 如果目录不存在,truename将不起作用 在S

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

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

目标是将其传递给
uiop:runprogram
,这样做似乎不对


回答如下:

=>错了

多谢各位


编辑我将分享更多内容

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

如果目录不存在,
truename
将不起作用

在SBCL上,
(名称字符串“~/doesntexist”)
也返回其波浪号

合并路径名
不起作用,仍然是波浪线问题

输入
确保目录存在
,并使用此结果创建名为
~
的目录

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

;; 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实现可能支持也可能不支持tilde语法

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

(truename "~/projects")
 => /home/user/projects
如果您的实现没有,或者如果您希望代码可移植,则必须相对于
(用户homedir路径名)

注意,如果支持tilde,那么它似乎只支持用作路径名的字符串,而不支持在目录组件中使用<代码>(:relative“~”的工作方式与预期不同,它引用了一个名为“~”的目录

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

(make-pathname :directory '(:absolute (:home "root")))
=> #P"~root/"
扩展到不存在的路径名
truename
是否要求该对象存在

是的,如果您想要构建一个不存在的文件的绝对路径,那么您需要对存在的部分调用
truename
,并与之合并。 在您的情况下,这将是
(truename“~/”
,它与
(user homedir pathname)
相同

正如Rainer Joswig所指出的,在SBCL以外的实现上调用
namestring
会返回一个扩展的路径名,将
~
转换为
/home/user
。在SBCL中,必须调用
sbext: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不支持语法,请参阅以获取灵感。

uiop中有一个本机名称字符串函数,该函数应在所有实现中都可用:

(uiop:native-namestring "~/projects")
=> /home/user/projects

truename
会要求该对象存在吗?是的,如果目录不存在,
truename
会失败。我喜欢一个支持这个的解决方案。@RainerJoswig是的,如果路径名不存在,似乎没有可移植的方法来解析它,但是
truename
仍然可以在预期存在的部分上调用。
namestring
可以在许多理解
的实现中工作:CCL、ABCL、CLISP、ECL、LispWorks。SBCL返回tilde名称…在SBCL中打开的问题:请注意,这根本不是特定于CL的问题;通常,在路径离开用户的交互式、兼容POSIX的shell并由应用程序处理之前,tilde会被扩展。没有一个标准的UNIX工具可以进行平铺扩展——如果您运行
rm'~/foo.txt'
,它将在名为
~
的目录中查找文件——因此一般认为应用程序不会尝试将其放入范围。这是一个很好的提醒!太好了,谢谢!它还适用于不存在的目录名。
(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")))))
(uiop:native-namestring "~/projects")
=> /home/user/projects