Repita todos os arquivos em um diretório

274

Como escrevo um loop em ruby ​​para poder executar um bloco de código em cada arquivo?

Eu sou novo no ruby ​​e concluí que a maneira de fazer isso é fazer cada loop.
O arquivo ruby ​​será executado a partir de um diretório diferente do diretório em que desejo executar o loop.

Eu tentei o Dir.foreache não consegui fazê-lo funcionar.

Andrew
fonte
2
Você pode especificar o que aconteceu quando tentou fazê-lo funcionar? Qual código exato você tentou (ou o bloco relevante, se for longo)? Quais mensagens de erro você recebeu? Dir.foreachtrabalha para iterar sobre o conteúdo de um diretório, para que outras coisas estejam acontecendo.
Telêmaco 25/03
3
Se você quer somente os arquivos dentro do seu diretório, não se esqueça de teste para arquivos quando iteração sobre o conteúdo do diretório: do_something_with(entry) if File.file?(entry)
Glenn Jackman
3
Use 'img/*.{jpg,png,gif,jpeg}'para pegar várias extensões.
Benjamin Crouzier
Infelizmente, o @ChrisPeters parece improvável, pois o OP não está no site há mais de quatro anos.
Joe Kennedy

Respostas:

429

Como outros já disseram, Dir::foreaché uma boa opção aqui. No entanto, observe que Dir::foreache Dir::entriessempre incluirá .e ..(os diretórios atual e pai). Geralmente, você não deseja trabalhar neles, portanto, pode usar Dir::each_childou Dir::children(como sugerido por ma11hew28 ) ou fazer algo como isto:

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

Dir::foreache Dir::entries(assim como Dir::each_childe Dir::children) também incluem arquivos e diretórios ocultos. Muitas vezes, é isso que você deseja, mas se não for, precisará fazer algo para ignorá-las.

Como alternativa, convém pesquisar Dir::globquais fornecem correspondência simples de curinga:

Dir.glob('/path/to/dir/*.rb') do |rb_filename|
  # Do work on files & directories ending in .rb
end
Telêmaco
fonte
12
Use Dir.foreachse o diretório contiver um grande número de arquivos!
Tilo 29/08
5
obrigado! Mod pequeno para torná-lo ainda melhor:next if File.directory? item
mr.buttons
@ mr.buttons Isso nem sempre faz a coisa certa. Às vezes, as pessoas querem trabalhar em diretórios e arquivos. Forneci código para evitar listagens especiais para .ou ..porque as pessoas quase sempre querem ignorar essas duas.
Telemachus
3
@ Tilo: apenas por interesse, gostaria de explicar um pouco mais detalhadamente por quê? :)
mkataja
11
O @mkataja Dir.foreachitera em vez de criar uma matriz (potencialmente enorme) na frente (o que Dir.globfaz). Portanto, se o diretório for realmente grande, poderá fazer uma diferença de desempenho. Em circunstâncias normais, você não notaria, mas sob condições de estresse, isso pode ser absolutamente importante.
Telêmaco
99

Este é o meu método favorito para facilitar a leitura:

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

E você pode até estender isso para trabalhar em todos os arquivos em subdiretórios:

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

Dir também possui sintaxe mais curta para obter uma matriz de todos os arquivos do diretório:

Dir['dir/to/files/*'].each do |fname|
    # do something with fname
end
wawka
fonte
O que neste código impede que os diretórios também sejam usados ​​com fnameas iterações?
kayleeFrye_onDeck
26
Dir.foreach("/home/mydir") do |fname|
  puts fname
end
Fred
fonte
2
Como alternativa, use Dir # [] ou Dir # glob
Ryan Bigg
13

A biblioteca de localização foi projetada especificamente para esta tarefa: https://ruby-doc.org/stdlib-2.5.1/libdoc/find/rdoc/Find.html

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

Esta é uma biblioteca ruby ​​padrão, portanto deve estar disponível

Faisal
fonte
1
File.finddesce recursivamente o máximo que pode, começando de qualquer caminho que você indicar. Não tenho certeza de que é isso que o OP quer.
Telêmaco 25/03
Parece que não tenho acesso a esse método - Find.find? Preciso fazer o download de uma biblioteca para incluir esta funcionalidade?
azul-céu
@ user470184: "Find" é uma biblioteca ruby ​​padrão e deve estar disponível com a instalação padrão do ruby. No entanto, você precisa "exigir 'localizar'" antes de poder usá-lo.
Faisal
1
@Faisal Can I passar padrões glob como *.rbafind()
Ashhar Hasan
7

Eu gosto deste, que não foi mencionado acima.

require 'pathname'

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

O benefício é que você obtém um objeto Pathname em vez de uma string, para poder fazer coisas úteis e percorrer mais adiante.

skagedal
fonte
3
Dir.new('/my/dir').each do |name|
  ...
end
Nick Moore
fonte
1
Além de Dir.new ('/ my / dir'), há também Dir.entries ('/ my / dir'), mas Dir.foreach () é um pouco mais sucinto.
o homem de lata
5
@ZED Também Dir.foreachitera enquanto Dir.entriescria toda a matriz de uma só vez. Portanto, se o diretório é imenso, é menos um problema de memória. (Geralmente não um grande negócio, provavelmente, mas ainda assim ...)
Telêmaco
2

Para pular .& .., você pode usar Dir::each_child.

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

Dir::children retorna uma matriz dos nomes de arquivos.

ma11hew28
fonte