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?


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


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



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['**/*']

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)

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) } }

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?


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) }

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', '*'))

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


1
Ce n'est pas trop élégant et aurait besoin de quelques lignes de plus pour l'être
onebree
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.