Une seule ligne pour lister récursivement les répertoires dans Ruby?

96

Quel est le moyen le plus rapide et le plus optimisé d'obtenir un tableau des répertoires (à l'exclusion des fichiers) dans Ruby?

Que diriez-vous d'inclure des fichiers?

Lance Pollard
la source
2
Le plus rapide, le plus optimisé et le one-liner peuvent être en contradiction avec la lecture / maintenance. Et vous pouvez le découvrir en utilisant un benchmark et des tests rapides.
le Tin Man

Réponses:

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

Au lieu de cela, Dir.glob(foo)vous pouvez également écrire Dir[foo](mais Dir.globpeut également prendre un bloc, auquel cas il donnera chaque chemin au lieu de créer un tableau).

Documents sur Ruby Glob

sepp2k
la source
10
utiliser Dir.glob("**/")sauf si vous voulez également des liens symboliques
johannes
6
Qu'en est-il des fichiers et répertoires cachés?
alediaferia
6
Pour inclure des fichiers dotfiles dans les résultats de correspondance, utilisez l' File::FNM_DOTMATCHindicateur.
x-yuri
2
Merci @ x-yuri! Le drapeau btw est spécifié comme ceci:Dir.glob("**/*", File::FNM_DOTMATCH)
vlz
2
Voici la documentation: ruby-doc.org/core-2.2.0/Dir.html#method-c-glob
stephen.hanson
53

Je pense qu'aucune des solutions ici ne traite des répertoires cachés (par exemple '.test'):

require 'find'
Find.find('.') { |e| puts e if File.directory?(e) }
FelipeC
la source
Find.find('/tmp').collect {|_|_}Était utile pour moi
Alexander Bird
Soyez prudent avec Find, il ne suit pas les liens symboliques: stackoverflow.com/questions/3974087/…
leebutts
31

Pour la liste des répertoires, essayez

Dir['**/']

La liste des fichiers est plus difficile, car dans le répertoire Unix est également un fichier, vous devez donc tester le type ou supprimer les entrées de la liste retournée qui est parent d'autres entrées.

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

Et pour la liste de tous les fichiers et répertoires simplement

Dir['**/*']
MBO
la source
Notez qu'il a dit "inclure également les fichiers", pas "seulement les fichiers", vous n'avez donc pas besoin de supprimer les répertoires.
sepp2k
1
@ sepp2k Oui, j'ai raté cette partie quand je jouais avec irb. Mais je laisse ceci ici au cas où quelqu'un chercherait quelque chose de similaire :-)
MBO
7

Fast one doublure

Seuls les répertoires

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

Répertoires et fichiers normaux

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

Beau rubis pur

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
la source
1
Faux: Dir.glob ("# {RÉPERTOIRE} / ** / * /"). Map {| répertoire | Pathname.new (répertoire)}
Robert Ross
Quelqu'un peut-il expliquer la end.select {}.flatten()partie? J'aime la fonction dans son ensemble. Il semble que cela créera un tableau de tableaux? Serait-il possible de faire la elseifpartie avec: rec_path(child, file) << child.to_spour pouvoir l'assigner à un tableau et obtenir un tableau de chaînes? Merci!
MCP
7

Comme indiqué dans d'autres réponses ici, vous pouvez utiliser Dir.glob. Gardez à l'esprit que les dossiers peuvent contenir beaucoup de caractères étranges et que les arguments glob sont des modèles, donc certains caractères ont des significations spéciales. En tant que tel, il est dangereux de faire quelque chose comme ce qui suit:

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

Faites plutôt:

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

En PHP ou dans d'autres langages pour obtenir le contenu d'un répertoire et de tous ses sous-répertoires, vous devez écrire quelques lignes de code, mais en Ruby cela prend 2 lignes:

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

cela imprimera le contenu du répertoire courant et tous ses sous-répertoires.

Ou plus court, vous pouvez utiliser la ’**’notation:

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

Combien de lignes allez-vous écrire en PHP ou en Java pour obtenir le même résultat?

Ramesh
la source
13
Évalué pour le copier-coller directement de mustap.com/rubyzone_post_162_recursive-directory-listing sans citer la source ...
eckza
@kivetros J'ai modifié la réponse pour inclure la version archivée du lien :-)
onebree
0

Bien que ce ne soit pas une solution à une ligne, je pense que c'est la meilleure façon de le faire en utilisant des appels ruby.

Supprimez d'abord tous les fichiers de manière récursive
Deuxième supprimez tous les répertoires vides

Dir.glob("./logs/**/*").each { |file| File.delete(file) if File.file? file }
Dir.glob("./logs/**/*/").each { |directory| Dir.delete(directory) }
AccueilTurf
la source
3
Il / elle ne veut pas supprimer les fichiers / répertoires.
Darek Nędza
Comment faire cela pour les deux fichiers + répertoire sur une seule ligne?
vipin8169
0

Voici un exemple qui combine la découverte dynamique d'un répertoire de projet Rails avec Dir.glob:

dir = Dir.glob(Rails.root.join('app', 'assets', 'stylesheets', '*'))
shacker
la source
J'ai essayé ceci >> config.assets.paths << Rails.root.join("app", "assets", "*"), mais je ne pouvais toujours pas voir les sous-dossiers et les fichiers dans le dossier assets parRails.application.config.assets.paths
vipin8169
-1
Dir.open(Dir.pwd).map { |h| (File.file?(h) ? "#{h} - file" : "#{h} - folder") if h[0] != '.' }

les points renvoient nul, utilisez compact

ruvan
la source
1
Ce n'est pas trop élégant et aurait besoin de quelques lignes de plus pour l'être
onebree