Pregunta

Estoy usando OpenMCL en Darwin, y me gustaría hacer algo como:

(loop for f in (directory "somedir")
  collect (some-per-file-processing f))

Pero no puedo hacer que directorio devuelva otra cosa que no sea NIL , y parece que no puedo encontrar ninguna buena explicación en línea (aparte de " es diferente para cada sistema ").

¿Algún puntero?

¿Fue útil?

Solución

¿Su especificación de ruta de acceso contiene un comodín? El nombre de ruta de Common Lisp es algo difícil de comprender al principio, al menos para mí lo fue ... Como CLHS indica en la función directorio :

  

Si el pathspec no es wild, el   la lista resultante contendrá   cero o uno elementos.

Para que su ruta incluya un comodín, puede probar la función make-pathname, como

(directory (make-pathname :directory '(:absolute "srv" "hunchentoot") :name :wild :type "lisp"))

O incluso

(directory (make-pathname :directory '(:absolute "srv" "hunchentoot") :name :wild :type :wild))

Encontré que la biblioteca CL-FAD es una gran ayuda para tratar los nombres de ruta y el sistema de archivos. . En particular, su función list-directory podría ser más fácil para usar que la función de directorio estándar simple.

Otros consejos

Hay básicamente dos formas de especificar las rutas de acceso:

  • usando cadenas

Las cadenas dependen obviamente de la plataforma: sintaxis de Unix vs. sintaxis de Windows, por ejemplo.

"/Users/foo/bar.text"  is a valid pathname
"/Users/foo/*/foo.*"   is a valid pathname with two wildcards

Puede crear un objeto de ruta de acceso a partir de una cadena:

? (pathname "/Users/bar/foo.text")
#P"/Users/bar/foo.text"

El #p anterior asegura que se crea un objeto de ruta de acceso (y no una cadena) cuando lo lees.

? #P"/Users/bar/foo.text"
#P"/Users/bar/foo.text"

Por lo tanto, internamente, Common Lisp funciona con objetos de ruta de acceso, pero le permite usar cadenas normales y crea nombres de ruta de acceso a partir de ellos si es necesario.

Cuando Common Lisp ve una ruta de acceso que no tiene todos los componentes especificados (por ejemplo, falta el directorio), rellena los componentes del objeto de ruta de acceso que es el valor de variabel * DEFAULT-PATHNAME-DEFAULTS *.

Con la función DESCRIBIR puede ver los componentes de una ruta (aquí Clozure CL):

? (describe (pathname "/Users/bar/*.text"))
#P"/Users/bar/*.text"
Type: PATHNAME
Class: #<BUILT-IN-CLASS PATHNAME>
TYPE: (PATHNAME . #<CCL::CLASS-WRAPPER PATHNAME #x3000401D03BD>)
%PATHNAME-DIRECTORY: (:ABSOLUTE "Users" "bar")
%PATHNAME-NAME: :WILD
%PATHNAME-TYPE: "text"
%PHYSICAL-PATHNAME-VERSION: :NEWEST
%PHYSICAL-PATHNAME-DEVICE: NIL
  • utilizando las funciones Lisp que crean objetos de ruta de acceso

MAKE-PATHNAME es la función y se necesitan algunos argumentos de palabras clave para especificar los componentes.

A veces también es útil crear una nueva ruta basada en una existente:

(make-pathname :name "foo" :defaults (pathname "/Users/bar/baz.text"))

Si usa DIRECTORY, es útil usar una ruta con caracteres comodín. DIRECTORY luego devolverá una lista de rutas de acceso coincidentes. El nombre 'DIRECTORIO' es ligeramente engañoso, ya que DIRECTORIO no enumera los contenidos de un directorio, pero enumera las rutas de acceso coincidentes para (normalmente) una ruta con caracteres comodín. Los comodines pueden coincidir con una secuencia de caracteres en componentes como /foo/s*c/list*.l*" ;. También está el comodín **, que se usa para hacer coincidir partes de una jerarquía de directorios como /foo/**/test.lisp, que coincide con todos los archivos test.lisp en el directorio foo y sus subdirectorios.

(directory "/Users/foo/Lisp/**/*.lisp")

Lo anterior debe devolver una lista de todos los archivos 'lisp' en '/ Users / foo / Lisp /' y todos sus subdirectorios.

Para devolver los archivos .c en un solo directorio, use:

(directory "/Users/foo/c/src/*.c")

Tenga en cuenta que DIRECTORIO devuelve una lista de objetos de ruta de acceso (no una lista de cadenas).

? (directory (make-pathname
               :name "md5"
               :type :wild
               :directory '(:absolute "Lisp" "cl-http" "cl-http-342" "server")))
(#P"/Lisp/cl-http/cl-http-342/server/md5.lisp"
 #P"/Lisp/cl-http/cl-http-342/server/md5.xfasl")

Arriba utiliza un objeto de ruta de acceso creado por MAKE-PATHNAME. Devuelve todos los archivos que coinciden con /Lisp/cl-http/cl-http-342/server/md5.*.

Esto es lo mismo que:

(directory "/Lisp/cl-http/cl-http-342/server/md5.*")

que es más corto, pero depende de la sintaxis de la ruta de Unix.

La lista de directorios de implementación de la biblioteca Common Lisp moderna es IOLIB .

Funciona así:

CL-USER> (iolib.os:list-directory "/etc/apt")
(#/p/"trusted.gpg~" #/p/"secring.gpg" #/p/"trustdb.gpg" #/p/"sources.list"
 #/p/"sources.list~" #/p/"apt-file.conf" #/p/"apt.conf.d" #/p/"trusted.gpg"
 #/p/"sources.list.d")

Tenga en cuenta que no se requieren barras o comodines finales. Es muy robusto e incluso puede procesar nombres de archivos con caracteres Unicode codificados incorrectamente.

Diferencias en comparación con CL-FAD:

  • Los objetos que obtienes son rutas de archivos IOLIB, un reemplazo para las rutas de CL, que está más cerca de lo que hace el sistema operativo subyacente.
  • IOLIB implementa sus rutinas utilizando CFFI, por lo que funciona de la misma manera en todas las implementaciones de Lisp (siempre que IOLIB tenga un backend para el sistema operativo), en contraste con CL-FAD, que intenta abstraer la función DIRECTORY de la implementación con todo su peculiaridades.
  • A diferencia de CL-FAD, iolib trata correctamente con enlaces simbólicos (un problema importante con CL-FAD que lo hace virtualmente inutilizable en plataformas que no sean Windows IMHO).

Agregaré un ejemplo que funcione para mí, por el bien de un fragmento de código. Uso osicat (similar a cl-fad) y str .

editar : también con uiop: directory-files . str: contiene? se podría hacer con search .

;; searching for "ref".
(setf *data-directory* "~/books/lisp")
(remove-if-not (lambda (it)
                   (str:contains? "ref" (namestring it)))
                (osicat:list-directory *data-directory*))

devuelve

(#P"~/books/lisp/common-lisp-quick-reference-clqr-a4-booklet-all.pdf"
 #P"~/books/lisp/common-lisp-quick-reference-clqr-a4-consec.pdf"
 #P"~/books/lisp/commonLisp-interactive-approach-reference-buffalo.pdf")

Ciertamente se puede mejorar mi uso apropiado de comodines. Sin embargo, ese es un fragmento que puedes usar ahora mismo:)

Referencias:

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top