¿Una línea para enumerar directorios de forma recursiva en Ruby?

96

¿Cuál es la forma más rápida, optimizada y de una sola línea de obtener una matriz de directorios (excluyendo archivos) en Ruby?

¿Qué tal incluir archivos?

Lance Pollard
fuente
2
Más rápido, más optimizado y de una sola línea puede estar en desacuerdo con legible / mantenible. Y puede averiguarlo utilizando un punto de referencia y una prueba rápida.
The Tin Man

Respuestas:

180
Dir.glob("**/*/") # for directories
Dir.glob("**/*") # for all files

En lugar de Dir.glob(foo)usted también puede escribir Dir[foo](sin embargo Dir.globtambién puede tener un bloque, en cuyo caso se producirá cada ruta en lugar de crear una matriz).

Documentos de Ruby Glob

sepp2k
fuente
10
utilizar a Dir.glob("**/")menos que también desee enlaces simbólicos
johannes
6
¿Qué pasa con los archivos y directorios ocultos?
alediaferia
6
Para incluir archivos de puntos en los resultados de las coincidencias, use la File::FNM_DOTMATCHbandera.
x-yuri
2
¡Gracias @ x-yuri! La bandera por cierto se especifica así:Dir.glob("**/*", File::FNM_DOTMATCH)
vlz
2
Aquí está la documentación: ruby-doc.org/core-2.2.0/Dir.html#method-c-glob
stephen.hanson
53

Creo que ninguna de las soluciones aquí trata con directorios ocultos (por ejemplo, '.test'):

require 'find'
Find.find('.') { |e| puts e if File.directory?(e) }
FelipeC
fuente
Find.find('/tmp').collect {|_|_}Fue útil para mí
Alexander Bird
Tenga cuidado con Find, no sigue enlaces simbólicos: stackoverflow.com/questions/3974087/…
leebutts
31

Para obtener una lista de directorios, intente

Dir['**/']

La lista de archivos es más difícil, porque en Unix el directorio también es un archivo, por lo que debe probar el tipo o eliminar las entradas de la lista devuelta, que es padre de otras entradas.

Dir['**/*'].reject {|fn| File.directory?(fn) }

Y para una lista de todos los archivos y directorios simplemente

Dir['**/*']
MBO
fuente
Tenga en cuenta que dijo "también incluir archivos", no "solo archivos", por lo que no es necesario eliminar los directorios.
sepp2k
1
@ sepp2k Sí, me perdí esta parte cuando jugaba con irb. Pero dejo esto aquí en caso de que alguien pueda buscar algo similar :-)
MBO
7

Un trazador de líneas rápido

Solo directorios

`find -type d`.split("\n")

Directorios y archivos normales

`find -type d -or -type f`.split("\n")`

Rubí puro hermoso

require "pathname"

def rec_path(path, file= false)
  puts path
  path.children.collect do |child|
    if file and child.file?
      child
    elsif child.directory?
      rec_path(child, file) + [child]
    end
  end.select { |x| x }.flatten(1)
end

# only directories
rec_path(Pathname.new(dir), false)
# directories and normal files
rec_path(Pathname.new(dir), true)
johannes
fuente
1
Falso: Dir.glob ("# {DIRECTORIO} / ** / * /"). Map {| directorio | Pathname.new (directorio)}
Robert Ross
¿Alguien puede explicar la end.select {}.flatten()parte? Me gusta la función en general. ¿Parece que eso creará una matriz de matrices? ¿Sería posible hacer la elseifparte con: rec_path(child, file) << child.to_spara poder asignarlo a una matriz y obtener una matriz de cadenas? ¡Gracias!
MCP
7

Como se señaló en otras respuestas aquí, puede usar Dir.glob. Tenga en cuenta que las carpetas pueden tener muchos caracteres extraños y los argumentos globales son patrones, por lo que algunos caracteres tienen significados especiales. Como tal, no es seguro hacer algo como lo siguiente:

Dir.glob("#{folder}/**/*")

En su lugar, haz lo siguiente:

Dir.chdir(folder) { Dir.glob("**/*").map {|path| File.expand_path(path) } }
troelskn
fuente
2

En PHP u otros lenguajes para obtener el contenido de un directorio y todos sus subdirectorios, debes escribir algunas líneas de código, pero en Ruby se necesitan 2 líneas:

require 'find'
Find.find('./') do |f| p f end

esto imprimirá el contenido del directorio actual y todos sus subdirectorios.

O más corto, puede usar la ’**’notación:

p Dir['**/*.*']

¿Cuántas líneas escribirás en PHP o en Java para obtener el mismo resultado?

Ramesh
fuente
13
Se votó en contra por copiar y pegar directamente de mustap.com/rubyzone_post_162_recursive-directory-listing sin citar la fuente ...
eckza
@kivetros Edité la respuesta para incluir la versión archivada del enlace :-)
onebree
0

Aunque no es una solución de una línea, creo que esta es la mejor manera de hacerlo usando llamadas ruby.

Primero elimine todos los archivos de forma recursiva
Segundo elimine todos los directorios vacíos

Dir.glob("./logs/**/*").each { |file| File.delete(file) if File.file? file }
Dir.glob("./logs/**/*/").each { |directory| Dir.delete(directory) }
Terreno propio
fuente
3
No quiere borrar archivos / directorios.
Darek Nędza
¿Cómo hacer esto para ambos archivos + directorio en una sola línea?
vipin8169
0

Aquí hay un ejemplo que combina el descubrimiento dinámico de un directorio de proyecto Rails con Dir.glob:

dir = Dir.glob(Rails.root.join('app', 'assets', 'stylesheets', '*'))
coctelera
fuente
Intenté esto >> config.assets.paths << Rails.root.join("app", "assets", "*"), pero todavía no podía ver las subcarpetas y archivos dentro de la carpeta de activos porRails.application.config.assets.paths
vipin8169
-1
Dir.open(Dir.pwd).map { |h| (File.file?(h) ? "#{h} - file" : "#{h} - folder") if h[0] != '.' }

los puntos devuelven cero, use compacto

ruvan
fuente
1
Esto no es demasiado elegante, y necesitaría estar en algunas líneas más para serlo
onebree