Einzeiler zum rekursiven Auflisten von Verzeichnissen in Ruby?

96

Was ist der schnellste, optimierteste und einzeiligste Weg, um ein Array der Verzeichnisse (ohne Dateien) in Ruby abzurufen?

Wie wäre es mit Dateien?

Lance Pollard
quelle
2
Der schnellste, am besten optimierte und einzeiligste kann im Widerspruch zu lesbar / wartbar stehen. Und Sie können dies anhand eines Benchmarks und schneller Tests herausfinden.
Der Blechmann

Antworten:

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

Anstelle von können Dir.glob(foo)Sie auch schreiben Dir[foo]( Dir.globkann aber auch einen Block nehmen, in welchem ​​Fall es jeden Pfad ergibt, anstatt ein Array zu erstellen).

Ruby Glob Docs

sepp2k
quelle
10
Verwenden Dir.glob("**/")Sie, es sei denn, Sie möchten auch Symlinks
Johannes
6
Was ist mit versteckten Dateien und Verzeichnissen?
Alediaferia
6
Verwenden Sie das File::FNM_DOTMATCHFlag, um Punktedateien in die Übereinstimmungsergebnisse aufzunehmen .
X-Yuri
2
Danke @ x-yuri! Die Flagge wird übrigens wie folgt angegeben:Dir.glob("**/*", File::FNM_DOTMATCH)
vlz
2
Hier ist die Dokumentation: ruby-doc.org/core-2.2.0/Dir.html#method-c-glob
stephen.hanson
53

Ich glaube, keine der Lösungen hier befasst sich mit versteckten Verzeichnissen (zB '.test'):

require 'find'
Find.find('.') { |e| puts e if File.directory?(e) }
FelipeC
quelle
Find.find('/tmp').collect {|_|_}War hilfreich für mich
Alexander Bird
Seien Sie vorsichtig mit Find, es folgt keinen Symlinks: stackoverflow.com/questions/3974087/…
leebutts
31

Für eine Liste der Verzeichnisse versuchen Sie

Dir['**/']

Die Liste der Dateien ist schwieriger, da im Unix-Verzeichnis auch eine Datei vorhanden ist. Sie müssen daher den Typ testen oder Einträge aus der zurückgegebenen Liste entfernen, die anderen Einträgen übergeordnet ist.

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

Und für die Liste aller Dateien und Verzeichnisse einfach

Dir['**/*']
MBO
quelle
Beachten Sie, dass er sagte, "auch Dateien einschließen", nicht "nur Dateien", so dass Sie die Verzeichnisse nicht entfernen müssen.
sepp2k
1
@ sepp2k Ja, ich habe diesen Teil verpasst, als ich mit irb gespielt habe. Aber ich lasse dies hier für den Fall, dass jemand nach etwas Ähnlichem suchen könnte :-)
MBO
7

Schneller Einzeiler

Nur Verzeichnisse

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

Verzeichnisse und normale Dateien

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

Reiner schöner Rubin

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
quelle
1
False: Dir.glob ("# {DIRECTORY} / ** / * /"). Map {| directory | Pathname.new (Verzeichnis)}
Robert Ross
Kann jemand den end.select {}.flatten()Teil erklären ? Ich mag die Funktion insgesamt. Es sieht so aus, als würde dadurch ein Array von Arrays erstellt. Wäre es möglich, den elseifTeil mit: zu machen, rec_path(child, file) << child.to_sdamit Sie ihn einem Array zuweisen und ein Array von Zeichenfolgen erhalten können? Vielen Dank!
MCP
7

Wie in anderen Antworten hier angegeben, können Sie verwenden Dir.glob. Beachten Sie, dass Ordner viele seltsame Zeichen enthalten können und Glob-Argumente Muster sind, sodass einige Zeichen eine besondere Bedeutung haben. Daher ist es unsicher, Folgendes zu tun:

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

Tun Sie stattdessen:

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

In PHP oder anderen Sprachen müssen Sie einige Codezeilen schreiben, um den Inhalt eines Verzeichnisses und aller seiner Unterverzeichnisse abzurufen. In Ruby sind jedoch zwei Zeilen erforderlich:

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

Dadurch wird der Inhalt des aktuellen Verzeichnisses und aller seiner Unterverzeichnisse gedruckt.

Oder kürzer, Sie können die ’**’Notation verwenden:

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

Wie viele Zeilen werden Sie in PHP oder Java schreiben, um das gleiche Ergebnis zu erzielen?

Ramesh
quelle
13
Downvoted für das direkte Einfügen von Kopien von mustap.com/rubyzone_post_162_recursive-directory-listing ohne Angabe der Quelle ...
eckza
@kivetros Ich habe die Antwort so bearbeitet, dass sie die archivierte Version des Links enthält :-)
onebree
0

Obwohl dies keine einzeilige Lösung ist, denke ich, dass dies der beste Weg ist, dies mit Ruby-Anrufen zu tun.

Löschen Sie zuerst alle Dateien rekursiv.
Zweitens löschen Sie alle leeren Verzeichnisse

Dir.glob("./logs/**/*").each { |file| File.delete(file) if File.file? file }
Dir.glob("./logs/**/*/").each { |directory| Dir.delete(directory) }
HomeTurf
quelle
3
Er / sie möchte keine Dateien / Verzeichnisse löschen.
Darek Nędza
Wie mache ich das für beide Dateien + Verzeichnis in einer einzigen Zeile?
Vipin8169
0

Hier ist ein Beispiel, das die dynamische Erkennung eines Rails-Projektverzeichnisses mit Dir.glob kombiniert:

dir = Dir.glob(Rails.root.join('app', 'assets', 'stylesheets', '*'))
Shacker
quelle
Ich habe dies versucht >> config.assets.paths << Rails.root.join("app", "assets", "*"), konnte aber immer noch die Unterordner und Dateien im Assets-Ordner vonRails.application.config.assets.paths
vipin8169
-1
Dir.open(Dir.pwd).map { |h| (File.file?(h) ? "#{h} - file" : "#{h} - folder") if h[0] != '.' }

Punkte geben nichts zurück, verwenden Sie kompakt

Ruvan
quelle
1
Dies ist nicht zu elegant, und müsste in ein paar Zeilen mehr sein, um so zu sein
onebree