Следующее работает, и я думаю, что оно должно работать в большинстве реализаций (я пробовал это на LW на MacOS, SBCL на Linux и Clojure на MacOS).
(defun directory-pathname (p)
;; Everything but the file part: this should be called
;; non-file-pathname or something
(make-pathname :name nil :type nil :version nil
:defaults (pathname p)))
(defconstant +wild-file+
;; a completely wildcarded filename with no other components
(make-pathname :name ':wild
:type ':wild
:version ':wild))
(defun wild-directory (d)
;; Take the directory parts of D and return a pathname which matches
;; all files in tat directory.
;;
;; Actually we could just use D for the defaults since it's only
;; used for defaults and that's less consy, but never mind
(merge-pathnames +wild-file+ (directory-pathname d)))
Затем, например, (directory (wild-directory "/tmp/"))
вернет все в каталоге /tmp/
, а (directory (wild-directory (user-homedir-pathname)))
вернет все в вашем домашнем каталоге.
Однако обратите внимание, что (это явно очень зависит от реализации, но похоже, что все реализации, которые я использую, согласны с этим, и я согласен с их интерпретацией): (directory (wild-directory "/tmp"))
вернет все в /
потому что "/tmp"
в качестве пути означает «файл с именем tmp
в каталоге с именем /
». Как я уже сказал, я думаю, что это разумная интерпретация: имена путей, которые ссылаются на каталоги, заканчиваются на /
.
Также обратите внимание, что +wild-file+
действительно дикий: он не обрабатывает файлы, чьи имена начинаются с .
каким-либо особым образом. Я думаю, что существует довольно очевидная двусмысленность в том, как следует анализировать имена файлов, такие как /foo/bar/.x
, хотя все три реализации, которые я пробовал, принимают правильную интерпретацию: имя ".x"
и тип nil
(/foo/bar/.x.y
, кажется, разбирается с типом "y"
, что я думаю, также разумно).
В любом случае, когда вам нужно выполнить какую-либо серьезную манипуляцию с именем пути, уловка состоит в том, чтобы определить набор функций и констант-оболочек, которые вы затем используете, и за которыми вы можете скрыть зависимость от реализации (в этом случае зависимость от реализации как получить все файлы в каталоге, все остальное, похоже, является общим для реализаций).
Я подозреваю, что такой уровень абстракции существует, но, к сожалению, я не знаю, что это такое.
После написания этого я попробовал CLISP, и он делает что-то интересное: похоже, что directory
не возвращает имена подкаталогов, только имена файлов. Я думаю, что это вполне разумная реализация, но она потребует еще большей абстракции.