如何在 Common Lisp 中将子目录附加到路径名
How to append a subdirectory to a pathname in Common Lisp
我在使用 Common Lisp(使用 SBCL)进行路径操作时遇到了一些问题。我正在尝试将子目录名称附加到我拥有的绝对路径名。
示例:我是 运行 我在目录 #P"/home/me/somedir" 中的 repl,我将“otherdir”作为变量,我想要的是 #P"/home/me/somedir/ otherdir
本质上,我试图将我在 Python 中的做法翻译成 Common Lisp:os.path.join(os.getcwd(), "otherdir")
我试过 (merge-pathnames (sb-posix:getcwd) "otherdir/")
但我只是找回了 cwd。如果我尝试 (merge-pathnames "otherdir/" (sb-posix:getcwd))
,我会在最后一个目录之前添加 otherdir/:#P"/home/me/otherdir/somedir"
我也尝试过使用 (make-pathname :directory '(:relative "otherdir") :defaults (sb-posix:getcwd))
,但我得到的却是#P""otherdir/somedir"。
有谁知道如何在 Common Lisp 中以编程方式建立路径?
>(merge-pathnames "otherdir" #P"/home/me/somedir/")
#P"/home/me/somedir/otherdir"
啊,路径处理之谜......你几乎已经用 merge-pathnames
,但第二个参数必须有尾随 /
:
(sb-posix:getcwd)
"/home/vince/projets"
=> 没有尾随 /
,因此当使用 otherdir/
(尾随斜线)或 otherdir
:
时我们会得到 2 个意想不到的结果
(merge-pathnames "otherdir/" (sb-posix:getcwd))
#P"/home/vince/otherdir/projets"
;; ^^
(merge-pathnames "otherdir" (sb-posix:getcwd))
#P"/home/vince/otherdir" ;; no "projets"
让我们在右边使用尾随/
:
(merge-pathnames "otherdir" "/home/vince/projets/")
#P"/home/vince/projets/otherdir" ;; <= expected
那么还有更“正确”的cwd
吗?通常,解决方案由 UIOP 给出(在 ASDF 中提供,因此始终可用)。
TBH我以前不知道,但我查了一下:
(apropos "cwd")
:GETCWD (bound)
OSICAT::CWD
OSICAT-POSIX::%GETCWD (fbound)
OSICAT-POSIX:GETCWD (fbound)
SB-POSIX:GETCWD (fbound)
SB-UNIX:POSIX-GETCWD (fbound)
SB-UNIX:POSIX-GETCWD/ (fbound)
SB-X86-64-ASM::CWD (fbound)
SB-X86-64-ASM::CWDE (fbound)
UIOP/FILESYSTEM::CWD
UIOP/OS:GETCWD (fbound)
(YMMV)
所以:
(UIOP/OS:GETCWD)
#P"/home/vince/projets/"
;; ^ yes!
等等,
解决方案
(merge-pathnames "otherdir" (UIOP/OS:GETCWD))
#P"/home/vince/projets/otherdir"
UIOP 是一个可移植的库。 SBCL 的实现是什么?查看来源(M-.
):
(sb-ext:parse-native-namestring (sb-unix:posix-getcwd/))
从现有路径构建新路径
注意:对于 Common Lisp UNIX 目录,通常在末尾有一个斜杠。
函数 PATHNAME
解析文件名字符串和 returns 路径名对象。
在 Mac:
上使用 SBCL
CL-USER> (pathname "/Users/foo/bar/")
#P"/Users/foo/bar/"
CL-USER> (merge-pathnames "baz/" *)
#P"/Users/foo/bar/baz/"
或
CL-USER> (let ((p (pathname "/Users/foo/bar/")))
(make-pathname :defaults p
:directory (append (pathname-directory p)
(list "baz"))))
#P"/Users/foo/bar/baz/"
作为 Lisp 对象的 UNIX 路径名
路径名是一个结构化对象,它也有一个目录组件。其他组件有:device、host、name、type, 版本。路径名对象的绝对目录组件如下所示:
CL-USER > (pathname-directory (pathname "/Users/foo/bar/"))
(:ABSOLUTE "Users" "foo" "bar")
这是一个以关键字 :absolute
开头的列表,后面是字符串形式的目录名称。
如果我们省略尾部斜杠,那么 PATHNAME
函数将以不同方式解析文件名:最后一个组件将是名称:
CL-USER > (pathname-directory (pathname "/Users/foo/bar"))
(:ABSOLUTE "Users" "foo")
CL-USER > (pathname-name (pathname "/Users/foo/bar"))
"bar"
我在使用 Common Lisp(使用 SBCL)进行路径操作时遇到了一些问题。我正在尝试将子目录名称附加到我拥有的绝对路径名。
示例:我是 运行 我在目录 #P"/home/me/somedir" 中的 repl,我将“otherdir”作为变量,我想要的是 #P"/home/me/somedir/ otherdir
本质上,我试图将我在 Python 中的做法翻译成 Common Lisp:os.path.join(os.getcwd(), "otherdir")
我试过 (merge-pathnames (sb-posix:getcwd) "otherdir/")
但我只是找回了 cwd。如果我尝试 (merge-pathnames "otherdir/" (sb-posix:getcwd))
,我会在最后一个目录之前添加 otherdir/:#P"/home/me/otherdir/somedir"
我也尝试过使用 (make-pathname :directory '(:relative "otherdir") :defaults (sb-posix:getcwd))
,但我得到的却是#P""otherdir/somedir"。
有谁知道如何在 Common Lisp 中以编程方式建立路径?
>(merge-pathnames "otherdir" #P"/home/me/somedir/")
#P"/home/me/somedir/otherdir"
啊,路径处理之谜......你几乎已经用 merge-pathnames
,但第二个参数必须有尾随 /
:
(sb-posix:getcwd)
"/home/vince/projets"
=> 没有尾随 /
,因此当使用 otherdir/
(尾随斜线)或 otherdir
:
(merge-pathnames "otherdir/" (sb-posix:getcwd))
#P"/home/vince/otherdir/projets"
;; ^^
(merge-pathnames "otherdir" (sb-posix:getcwd))
#P"/home/vince/otherdir" ;; no "projets"
让我们在右边使用尾随/
:
(merge-pathnames "otherdir" "/home/vince/projets/")
#P"/home/vince/projets/otherdir" ;; <= expected
那么还有更“正确”的cwd
吗?通常,解决方案由 UIOP 给出(在 ASDF 中提供,因此始终可用)。
TBH我以前不知道,但我查了一下:
(apropos "cwd")
:GETCWD (bound)
OSICAT::CWD
OSICAT-POSIX::%GETCWD (fbound)
OSICAT-POSIX:GETCWD (fbound)
SB-POSIX:GETCWD (fbound)
SB-UNIX:POSIX-GETCWD (fbound)
SB-UNIX:POSIX-GETCWD/ (fbound)
SB-X86-64-ASM::CWD (fbound)
SB-X86-64-ASM::CWDE (fbound)
UIOP/FILESYSTEM::CWD
UIOP/OS:GETCWD (fbound)
(YMMV)
所以:
(UIOP/OS:GETCWD)
#P"/home/vince/projets/"
;; ^ yes!
等等,
解决方案
(merge-pathnames "otherdir" (UIOP/OS:GETCWD))
#P"/home/vince/projets/otherdir"
UIOP 是一个可移植的库。 SBCL 的实现是什么?查看来源(M-.
):
(sb-ext:parse-native-namestring (sb-unix:posix-getcwd/))
从现有路径构建新路径
注意:对于 Common Lisp UNIX 目录,通常在末尾有一个斜杠。
函数 PATHNAME
解析文件名字符串和 returns 路径名对象。
在 Mac:
上使用 SBCLCL-USER> (pathname "/Users/foo/bar/")
#P"/Users/foo/bar/"
CL-USER> (merge-pathnames "baz/" *)
#P"/Users/foo/bar/baz/"
或
CL-USER> (let ((p (pathname "/Users/foo/bar/")))
(make-pathname :defaults p
:directory (append (pathname-directory p)
(list "baz"))))
#P"/Users/foo/bar/baz/"
作为 Lisp 对象的 UNIX 路径名
路径名是一个结构化对象,它也有一个目录组件。其他组件有:device、host、name、type, 版本。路径名对象的绝对目录组件如下所示:
CL-USER > (pathname-directory (pathname "/Users/foo/bar/"))
(:ABSOLUTE "Users" "foo" "bar")
这是一个以关键字 :absolute
开头的列表,后面是字符串形式的目录名称。
如果我们省略尾部斜杠,那么 PATHNAME
函数将以不同方式解析文件名:最后一个组件将是名称:
CL-USER > (pathname-directory (pathname "/Users/foo/bar"))
(:ABSOLUTE "Users" "foo")
CL-USER > (pathname-name (pathname "/Users/foo/bar"))
"bar"