Durchlaufen Sie jede Datei in einem Verzeichnis

274

Wie schreibe ich eine Schleife in Ruby, damit ich für jede Datei einen Codeblock ausführen kann?

Ich bin neu in Ruby und bin zu dem Schluss gekommen, dass der Weg, dies zu tun, darin besteht, jede Schleife zu machen.
Die Ruby-Datei wird aus einem anderen Verzeichnis als dem Verzeichnis ausgeführt, das ich durchlaufen möchte.

Ich habe es versucht Dir.foreachund konnte es nicht zum Laufen bringen.

Andrew
quelle
2
Können Sie angeben, was passiert ist, als Sie versucht haben, es zum Laufen zu bringen? Welchen genauen Code haben Sie ausprobiert (oder den entsprechenden Block, wenn er lang ist)? Welche Fehlermeldungen haben Sie erhalten? Dir.foreacharbeitet, um über den Inhalt eines Verzeichnisses zu iterieren, so dass etwas anderes viel los ist.
Telemachos
3
Wenn Sie nur Dateien in Ihrem Verzeichnis haben möchten, vergessen Sie nicht, beim Durchlaufen des Verzeichnisinhalts nach Dateien zu do_something_with(entry) if File.file?(entry)
suchen
3
Verwenden Sie 'img/*.{jpg,png,gif,jpeg}'diese Option, um mehrere Erweiterungen abzurufen.
Benjamin Crouzier
@ChrisPeters scheint leider unwahrscheinlich, da das OP seit über vier Jahren nicht mehr auf der Website war.
Joe Kennedy

Antworten:

429

Wie andere gesagt haben, Dir::foreachist hier eine gute Option. Beachten Sie jedoch, dass Dir::foreachund Dir::entriesimmer .und ..(das aktuelle und das übergeordnete Verzeichnis) enthalten sind. Sie werden im Allgemeinen nicht daran arbeiten wollen, also können Sie Dir::each_childoder Dir::children(wie von ma11hew28 vorgeschlagen ) verwenden oder so etwas tun:

Dir.foreach('/path/to/dir') do |filename|
  next if filename == '.' or filename == '..'
  # Do work on the remaining files & directories
end

Dir::foreachund Dir::entries(sowie Dir::each_childund Dir::children) enthalten auch versteckte Dateien und Verzeichnisse. Oft ist es das, was Sie wollen, aber wenn dies nicht der Fall ist, müssen Sie etwas tun, um sie zu überspringen.

Alternativ können Sie sich ansehen, Dir::globwelche einfache Platzhalterübereinstimmung bietet:

Dir.glob('/path/to/dir/*.rb') do |rb_filename|
  # Do work on files & directories ending in .rb
end
Telemachos
quelle
12
Verwenden Sie Dir.foreachdiese Option, wenn das Verzeichnis eine große Anzahl von Dateien enthält!
Tilo
5
Vielen Dank! Kleiner Mod, um es noch besser zu machen:next if File.directory? item
mr.buttons
@ mr.buttons Das wird nicht immer das Richtige tun. Manchmal möchten Leute sowohl an Verzeichnissen als auch an Dateien arbeiten. Ich habe Code gegeben, um die speziellen Einträge für .oder ..weil die Leute diese beiden fast immer ignorieren wollen, zu vermeiden .
Telemachos
3
@ Tilo: Nur aus Interesse, möchten Sie etwas genauer erklären, warum? :)
mkataja
11
@mkataja Dir.foreachiteriert, anstatt ein (möglicherweise riesiges) Array im Voraus aufzubauen (was der Dir.globFall ist). Wenn das Verzeichnis also wirklich riesig ist, kann dies einen Leistungsunterschied bewirken. Unter normalen Umständen würden Sie es nicht bemerken, aber unter Stressbedingungen kann es absolut wichtig sein.
Telemachos
99

Dies ist meine Lieblingsmethode, um leicht zu lesen:

Dir.glob("*/*.txt") do |my_text_file|
  puts "working on: #{my_text_file}..."
end

Und Sie können dies sogar erweitern, um alle Dateien in Unterverzeichnissen zu bearbeiten:

Dir.glob("**/*.txt") do |my_text_file| # note one extra "*"
  puts "working on: #{my_text_file}..."
end
Einfach
quelle
30

Dir hat auch eine kürzere Syntax, um ein Array aller Dateien aus dem Verzeichnis abzurufen:

Dir['dir/to/files/*'].each do |fname|
    # do something with fname
end
wawka
quelle
Was in diesem Code verhindert, dass Verzeichnisse auch mit fnameIterationen verwendet werden?
KayleeFrye_onDeck
26
Dir.foreach("/home/mydir") do |fname|
  puts fname
end
Fred
quelle
2
Alternativ können Sie Dir # [] oder Dir # glob
Ryan Bigg
13

Die Suchbibliothek wurde speziell für diese Aufgabe entwickelt: https://ruby-doc.org/stdlib-2.5.1/libdoc/find/rdoc/Find.html

require 'find'
Find.find(path) do |file|
  # process
end

Dies ist eine Standard-Ruby-Bibliothek, daher sollte sie verfügbar sein

Faisal
quelle
1
File.findgeht rekursiv so weit wie möglich nach unten, beginnend mit dem Pfad, den Sie ihm geben. Ich bin mir nicht sicher, ob das OP das will.
Telemachos
Ich habe anscheinend keinen Zugriff auf diese Methode - Find.find? Muss ich eine Bibliothek herunterladen, um diese Funktionalität einzuschließen?
blauer Himmel
@ user470184: "Suchen" ist eine Standard-Ruby-Bibliothek und sollte mit der Standard-Ruby-Installation verfügbar sein. Sie müssen jedoch "find 'benötigen", bevor Sie es verwenden können.
Faisal
1
@Faisal Kann ich Glob Muster wie *.rbzu übergebenfind()
Ashhar Hasan
7

Ich mag dieses, das oben nicht erwähnt wurde.

require 'pathname'

Pathname.new('/my/dir').children.each do |path|
    puts path
end

Der Vorteil ist, dass Sie anstelle einer Zeichenfolge ein Pfadnamenobjekt erhalten, mit dem Sie nützliche Dinge tun und weiter durchlaufen können.

skagedal
quelle
3
Dir.new('/my/dir').each do |name|
  ...
end
Nick Moore
quelle
1
Neben Dir.new ('/ my / dir') gibt es auch Dir.entries ('/ my / dir'), aber Dir.foreach () ist etwas prägnanter.
der Blechmann
5
@ZED Dir.foreachIteriert auch, während Dir.entriesdas gesamte Array auf einmal aufgebaut wird. Wenn das Verzeichnis also immens ist, ist es weniger ein Speicher-Hit. (Normalerweise keine große Sache, wahrscheinlich, aber immer noch ...)
Telemachus
2

Zum Überspringen von .& ..können Sie verwenden Dir::each_child.

Dir.each_child('/path/to/dir') do |filename|
  puts filename
end

Dir::children Gibt ein Array der Dateinamen zurück.

ma11hew28
quelle