Ulangi setiap file dalam satu direktori

274

Bagaimana cara saya menulis loop di ruby ​​sehingga saya dapat menjalankan blok kode pada setiap file?

Saya baru untuk ruby, dan saya telah menyimpulkan bahwa cara untuk melakukan ini adalah melakukan setiap loop.
File ruby ​​akan dieksekusi dari direktori yang berbeda dari direktori yang ingin saya loop.

Saya sudah mencoba Dir.foreachdan saya tidak bisa membuatnya bekerja.

Andrew
sumber
2
Bisakah Anda menentukan apa yang terjadi ketika Anda mencoba membuatnya berfungsi? Kode persis apa yang Anda coba (atau potongan yang relevan, jika panjang)? Pesan kesalahan apa yang Anda dapatkan? Dir.foreachberfungsi untuk beralih pada isi direktori, jadi sesuatu yang lain sedang terjadi.
Telemakus
3
Jika Anda hanya ingin file di dalam direktori Anda, jangan lupa untuk menguji file ketika mengulangi isi direktori: do_something_with(entry) if File.file?(entry)
glenn jackman
3
Gunakan 'img/*.{jpg,png,gif,jpeg}'untuk mengambil banyak ekstensi.
Benjamin Crouzier
@ChrisPeters tampaknya tidak mungkin sayangnya, karena OP belum berada di situs selama lebih dari empat tahun.
Joe Kennedy

Jawaban:

430

Seperti yang orang lain katakan, Dir::foreachadalah pilihan yang bagus di sini. Namun, perhatikan bahwa Dir::foreachdan Dir::entriesakan selalu menyertakan .dan ..(direktori saat ini dan orang tua). Anda umumnya tidak ingin mengerjakannya, sehingga Anda dapat menggunakan Dir::each_childatau Dir::children(seperti yang disarankan oleh ma11hew28 ) atau melakukan sesuatu seperti ini:

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

Dir::foreachdan Dir::entries(serta Dir::each_childdan Dir::children) juga menyertakan file & direktori tersembunyi. Seringkali ini yang Anda inginkan, tetapi jika tidak, Anda perlu melakukan sesuatu untuk melompati mereka.

Atau, Anda mungkin ingin melihat Dir::globyang menyediakan pencocokan wildcard sederhana:

Dir.glob('/path/to/dir/*.rb') do |rb_filename|
  # Do work on files & directories ending in .rb
end
Telemakus
sumber
12
Gunakan Dir.foreachjika direktori berisi sejumlah besar file!
Tilo
5
Terima kasih! Mod kecil untuk membuatnya lebih baik:next if File.directory? item
mr.buttons
@ mr.buttons Itu tidak akan selalu melakukan hal yang benar. Terkadang orang ingin mengerjakan direktori dan juga file. Saya memberi kode untuk menghindari daftar khusus untuk .atau ..karena orang hampir selalu ingin mengabaikan keduanya.
Telemakus
3
@Tilo: hanya karena ketertarikan, ingin menjelaskan sedikit lebih detail mengapa? :)
mkataja
11
@mkataja Dir.foreachiterates daripada membangun array (berpotensi besar) di depan (yang Dir.globtidak). Jadi, jika direktori sangat besar, itu dapat membuat perbedaan kinerja. Dalam keadaan normal Anda tidak akan menyadarinya, tetapi dalam kondisi stres, itu bisa sangat berarti.
Telemachus
99

Ini adalah metode favorit saya agar mudah dibaca:

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

Dan Anda bahkan dapat memperluas ini untuk bekerja pada semua file di subdirektori:

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

Dir juga memiliki sintaks yang lebih pendek untuk mendapatkan array dari semua file dari direktori:

Dir['dir/to/files/*'].each do |fname|
    # do something with fname
end
wawka
sumber
Apa dalam kode ini yang mencegah direktori dari juga digunakan dengan fnameiterasi?
kayleeFrye_onDeck
26
Dir.foreach("/home/mydir") do |fname|
  puts fname
end
Fred
sumber
2
Atau gunakan Dir # [] atau Dir # glob
Ryan Bigg
13

Pustaka find dirancang untuk tugas ini secara khusus: https://ruby-doc.org/stdlib-2.5.1/libdoc/find/rdoc/Find.html

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

Ini adalah perpustakaan ruby ​​standar, jadi itu harus tersedia

Faisal
sumber
1
File.findberjalan secara rekursif sejauh mungkin, mulai dari jalan apa pun yang Anda berikan. Saya tidak yakin itu yang diinginkan OP.
Telemakus
Saya sepertinya tidak memiliki akses ke metode itu - Find.find? Apakah saya perlu mengunduh perpustakaan atau menyertakan fungsi ini?
langit biru
@ user470184: "Temukan" adalah pustaka ruby ​​standar dan harus tersedia dengan instalasi ruby ​​default. Namun, Anda perlu "meminta 'menemukan'" sebelum dapat menggunakannya.
Faisal
1
@Faisal Can saya lulus pola gumpal seperti *.rbkefind()
Ashhar Hasan
7

Saya suka yang ini, yang belum disebutkan di atas.

require 'pathname'

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

Keuntungannya adalah Anda mendapatkan objek Pathname alih-alih string, yang dapat Anda lakukan dengan hal-hal yang bermanfaat dan melintasi lebih jauh.

skagedal
sumber
3
Dir.new('/my/dir').each do |name|
  ...
end
Nick Moore
sumber
1
Selain Dir.new ('/ my / dir') ada juga Dir.entries ('/ my / dir') tetapi Dir.foreach () sedikit lebih ringkas.
the Tin Man
5
@ ZED Juga Dir.foreachmengulang sementara Dir.entriesmembangun seluruh array sekaligus. Jadi, jika direktori tersebut sangat besar, itu bukan memori hit. (Biasanya bukan masalah besar, mungkin, tapi tetap saja ...)
Telemachus
2

Untuk melewati .& .., Anda dapat menggunakan Dir::each_child.

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

Dir::children mengembalikan array nama file.

ma11hew28
sumber