如何在 Common Lisp 中将子目录附加到路径名

发布于 2025-01-14 18:33:01 字数 648 浏览 4 评论 0原文

我在 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"

I也尝试过使用 (make-pathname :directory '(:relative "otherdir") :defaults (sb-posix:getcwd)) 但我却得到#P“其他目录/某些目录”。

有谁知道如何在 Common Lisp 中以编程方式构建路径?

I'm having some trouble with path manipulation in Common Lisp (using SBCL). I'm trying to append a subdirectory name to an absolute pathname that I have.

Example: I am running my repl in directory #P"/home/me/somedir" and I have "otherdir" as a variable and what I want is #P"/home/me/somedir/otherdir"

Essentially, I'm trying to translate how I'd do this in Python into Common Lisp: os.path.join(os.getcwd(), "otherdir")

I've tried (merge-pathnames (sb-posix:getcwd) "otherdir/") but I just get the cwd back. If I try (merge-pathnames "otherdir/" (sb-posix:getcwd)) I instead get otherdir/ prepended before the last directory: #P"/home/me/otherdir/somedir"

I've also tried using (make-pathname :directory '(:relative "otherdir") :defaults (sb-posix:getcwd)) but I instead get #P"otherdir/somedir".

Does anyone know how to build up a path programmatically in Common Lisp?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

陪你搞怪i 2025-01-21 18:33:01

啊,路径处理之谜……你已经用 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 中提供,因此总是可用的)。

说实话,我以前不知道,但我查了一下:

(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/))

Ah, path handling mysteries… you were nearly there with merge-pathnames, but the second argument must have a trailing /:

(sb-posix:getcwd)
"/home/vince/projets"

=> no trailing /, so accordingly we get 2 unexpected results when using otherdir/ (trailing slash) or otherdir:

(merge-pathnames "otherdir/" (sb-posix:getcwd))
#P"/home/vince/otherdir/projets"
;;                      ^^

(merge-pathnames "otherdir" (sb-posix:getcwd))
#P"/home/vince/otherdir"  ;; no "projets"

Let's use a trailing / on the right:

(merge-pathnames "otherdir" "/home/vince/projets/")
#P"/home/vince/projets/otherdir"  ;; <= expected

So is there a more "correct" cwd? As often, the solution is given by UIOP (shipped in ASDF, so always available).

TBH I didn't know it before, but I looked it up:

(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)

So:

(UIOP/OS:GETCWD)
#P"/home/vince/projets/"
;;                    ^ yes!

and so,

The solution

(merge-pathnames "otherdir" (UIOP/OS:GETCWD))
#P"/home/vince/projets/otherdir"

UIOP is a portable library. What's the implementation for SBCL? Looking at the source (M-.):

(sb-ext:parse-native-namestring (sb-unix:posix-getcwd/))
秋千易 2025-01-21 18:33:01
>(merge-pathnames "otherdir" #P"/home/me/somedir/")
#P"/home/me/somedir/otherdir"
>(merge-pathnames "otherdir" #P"/home/me/somedir/")
#P"/home/me/somedir/otherdir"
醉城メ夜风 2025-01-21 18:33:01

从现有路径名构造新路径名

注意:对于 Common Lisp UNIX 目录,通常在末尾有一个斜杠。

函数PATHNAME 解析文件名字符串并返回路径名对象。

在 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 路径名

路径名是一个结构化对象,它还具有一个目录组件。其他组件包括:设备主机名称类型、版本。路径名对象的绝对目录组件如下所示:

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"

Constructing new pathnames from existing ones

Note: For Common Lisp UNIX directories usually have a slash at the end.

The function PATHNAME parses a filename string and returns a pathname object.

Using SBCL on a Mac:

CL-USER> (pathname "/Users/foo/bar/")
#P"/Users/foo/bar/"

CL-USER> (merge-pathnames "baz/" *)
#P"/Users/foo/bar/baz/"

or

CL-USER> (let ((p (pathname "/Users/foo/bar/")))
           (make-pathname :defaults p
                          :directory (append (pathname-directory p)
                                             (list "baz"))))
#P"/Users/foo/bar/baz/"

UNIX Pathnames as Lisp objects

A pathname is a structured object, which also has a directory component. Other components are: device, host, name, type, version. An absolute directory component of a pathname object looks like this:

CL-USER > (pathname-directory (pathname "/Users/foo/bar/"))
(:ABSOLUTE "Users" "foo" "bar")

It's a list beginning with the keyword :absolute, followed by the directory names as strings.

If we omit the trailing slash, then the PATHNAME function will parse the filename differently: the last component will be the name:

CL-USER > (pathname-directory (pathname "/Users/foo/bar"))
(:ABSOLUTE "Users" "foo")

CL-USER > (pathname-name (pathname "/Users/foo/bar"))
"bar"
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文