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