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?


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


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



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

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)

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

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?


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

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

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


1
Dies ist nicht zu elegant, und müsste in ein paar Zeilen mehr sein, um so zu sein
onebree
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.