Ruby를 사용하여 폴더에서 모든 파일 이름 가져 오기


답변:


537

바로 가기 옵션도 있습니다

Dir["/path/to/search/*"]

폴더 또는 하위 폴더에서 모든 Ruby 파일을 찾으려면 다음을 수행하십시오.

Dir["/path/to/search/**/*.rb"]

5
또는 당신은 디렉터리와 같은 작업을 수행 할 수 있습니다 : 글로브 ()
— 요안 르 감동적

2
또한, ./...대신 사용하십시오~/
— Minh Triet

5
이것이 왜 선호됩니까?
— BvuRVKyUVlViVIc7

1
@MinhTriet 그게 뭐죠? 바람직한 것은 무엇입니까?
— stephenmurdoch

9
@marflar- ./현재 디렉토리를 의미하는 반면 /루트 마운트 지점이며 ~/사용자의 홈 디렉토리입니다. 전체 프로젝트를 다른 곳으로 옮기면 첫 번째 프로젝트는 작동하지만 다른 두 프로젝트는 효과가 없습니다.
— mirichan

170
Dir.entries(folder)

예:

Dir.entries(".")

출처 : http://ruby-doc.org/core/classes/Dir.html#method-c-entries


15
그가 방금 질문 한 질문에 대한 답변을 문서화하기 위해 SO를 사용하고있는 것 같습니다. 일종의 메모라고 생각합니다. 이것으로 많은 것을 잘못 볼 수는 없습니다. 결국 비록 조금 불완전하지만 ( Dir#glob예를 들어 언급되었을 수도 있습니다) 다른 사람이 정말 좋은 답변을 게시하는 것을 막을 수있는 것은 없습니다. '과정, 나는 주로 "유리 반 전체"일종의 남자 ...
— Mike Woodhouse

1
@ 마이크 : 대단한 계획에서 아마도 큰 문제는 아닙니다. 질문과 답변이 좋으면 사이트 전체에 도움이 될 수 있습니다. 그러나 여기에 질문과 답변이 너무 작아서 특히 유용하지 않습니다.
— Telemachus

17
@ Telemachus 나는 Dir거의 사용 하지 않으며 필요할 때마다 문서를 읽어야합니다. 내 질문과 답변을 여기에 게시하여 나중에 찾을 수 있으며 같은 질문을 가진 사람을 도울 수도 있습니다. SO 팟 캐스트에서 그런 행동에는 아무런 문제가 없다고 들었습니다. 더 나은 답변이 있으면 게시하십시오. 나는 내가 아는 것을 게시했다. 나는 루비 닌자가 아니다. 나는 가장 많은 표를 얻은 답변을 정기적으로 받아들입니다.
— Željko Filipin

이것은 인수가 변수 일 때보 다 Dir[]또는 더 나은 옵션 일 수 있습니다 Dir.glob. 때 path = '/tmp', 비교 : Dir.glob("#{path}/*")대 Dir.entries(path). 반환 값은 약간 다르지만 ( ".", "..") 후자는 한 눈에 파악하기가 더 쉽습니다.
— Benjamin Oakes

92

다음 조각은 정확히 디렉토리 내 파일을 건너 뛰는 하위 디렉토리 및 이름 표시 ".", ".."점으로 구분 된 폴더를 :

Dir.entries("your/folder").select {|f| !File.directory? f}

19
...select {|f| File.file? f}더 명확한 의미와 더 짧은 구문을 위해 할 수도 있습니다 .
— Automatico

2
@squixy 올바르게 작성 했습니까? :Dir.entries("your/folder").select {|f| File.file? f}
— Automatico

9
네. !File.directory?작동하지만 작동하지 File.file?않습니다.
— Kamil Lelonek

2
@ squixy 나는 같은 문제가 있었다, 내 경우에는 Dir.foreach에 의해 반환 된 파일 이름뿐만 아니라 전체 경로를 제공해야합니다
— TheLukeMcCarthy

6
.reject {|f| File.directory? f}보다 깨끗해 보입니다 .select{|f| !File.directory? f}. 아, 이제 첫 번째 의견도 보았습니다 ... 또한 좋습니다.
— Ian

36

모든 파일 (엄격한 파일 만)을 재귀 적으로 가져 오려면 :

Dir.glob('path/**/*').select{ |e| File.file? e }

또는 디렉토리 File.file?가 아닌 모든 것 ( 비정규 파일을 거부 함) :

Dir.glob('path/**/*').reject{ |e| File.directory? e }

대체 솔루션

실제로 Find#find패턴 기반 조회 방법을 사용 하는 Dir.glob것이 더 좋습니다. "루비에서 디렉토리를 재귀 적으로 나열하는 한 줄짜리"에 대한이 답변을 참조하십시오. .


18

이것은 나를 위해 작동합니다 :

숨겨진 파일을 원하지 않으면 [1] Dir []을 사용하십시오 .

# With a relative path, Dir[] will return relative paths 
# as `[ './myfile', ... ]`
#
Dir[ './*' ].select{ |f| File.file? f } 

# Want just the filename?
# as: [ 'myfile', ... ]
#
Dir[ '../*' ].select{ |f| File.file? f }.map{ |f| File.basename f }

# Turn them into absolute paths?
# [ '/path/to/myfile', ... ]
#
Dir[ '../*' ].select{ |f| File.file? f }.map{ |f| File.absolute_path f }

# With an absolute path, Dir[] will return absolute paths:
# as: [ '/home/../home/test/myfile', ... ]
#
Dir[ '/home/../home/test/*' ].select{ |f| File.file? f }

# Need the paths to be canonical?
# as: [ '/home/test/myfile', ... ]
#
Dir[ '/home/../home/test/*' ].select{ |f| File.file? f }.map{ |f| File.expand_path f }

이제 Dir.entries 는 숨겨진 파일을 반환하고 와일드 카드 별표 (디렉토리 이름으로 변수를 전달할 수 있음)는 필요하지 않지만 기본 이름을 직접 반환하므로 File.xxx 함수가 작동하지 않습니다. .

# In the current working dir:
#
Dir.entries( '.' ).select{ |f| File.file? f }

# In another directory, relative or otherwise, you need to transform the path 
# so it is either absolute, or relative to the current working dir to call File.xxx functions:
#
home = "/home/test"
Dir.entries( home ).select{ |f| File.file? File.join( home, f ) }

[1] .dotfile유닉스에서 나는 Windows에 대해 모른다



9

개인적으로, 이것은 폴더의 파일을 루핑 할 때 가장 유용한 것으로 나타났습니다.

Dir['/etc/path/*'].each do |file_name|
  next if File.directory? file_name 
end

9

이것은 디렉토리에서 파일을 찾는 솔루션입니다.

files = Dir["/work/myfolder/**/*.txt"]

files.each do |file_name|
  if !File.directory? file_name
    puts file_name
    File.open(file_name) do |file|
      file.each_line do |line|
        if line =~ /banco1/
          puts "Found: #{line}"
        end
      end
    end
  end
end

6

디렉토리의 모든 파일 이름을 가져 오는 동안이 스 니펫은 디렉토리 [ ., ..] 및로 시작하는 숨겨진 파일을 모두 거부하는 데 사용할 수 있습니다 ..

files = Dir.entries("your/folder").reject {|f| File.directory?(f) || f[0].include?('.')}

Dir.entries절대 파일 경로가 아닌 로컬 파일 이름을 반환합니다. 반면에 File.directory?절대 파일 경로가 필요합니다. 이 코드는 예상대로 작동하지 않습니다.
— Nathan

귀하의 경우 코드가 작동하지 않는 것이 이상합니다. 이 코드는 라이브 앱에서 사용한 코드이므로 정상적으로 작동합니다. 원래 작업 코드에서 누락 된 것이 있으면 코드를 다시 확인하고 여기에 게시하겠습니다. :)
— Lahiru

1
@Nathan 설명에 대한 내 대답보기


4

이것이 나를 위해 작동하는 것입니다.

Dir.entries(dir).select { |f| File.file?(File.join(dir, f)) }

Dir.entries문자열 배열을 반환합니다. 그런 다음 현재 작업 디렉토리와 동일 File.file?하지 않은 경우 파일의 전체 경로를 제공해야합니다 dir. 이것이 바로이 이유 File.join()입니다.


1
"."을 제외해야합니다. 및 항목에서 ".."
— Edgar Ortega

3

다음을 사용하고 싶을 수도 있습니다 Rake::FileList( rake종속성이있는 경우).

FileList.new('lib/*') do |file|
  p file
end

API에 따르면 :

FileLists가 게으르다. 파일 목록에 포함 할 수있는 파일에 대한 glob 패턴 목록이 제공되면 파일 구조를 검색하여 파일을 찾는 대신 FileList는 나중에 사용하기 위해 패턴을 보유합니다.

https://docs.ruby-lang.org/en/2.1.0/Rake/FileList.html


1

당신은 파일 이름의 배열을 취득하려는 경우 심볼릭 링크를 포함하여 , 사용

Dir.new('/path/to/dir').entries.reject { |f| File.directory? f }

또는

Dir.new('/path/to/dir').reject { |f| File.directory? f }

당신이 가고 싶은 경우 심볼릭 링크없이 사용

Dir.new('/path/to/dir').select { |f| File.file? f }

다른 답변에서 볼 수 있듯이 모든 파일을 재귀 적으로 얻으려면 Dir.glob('/path/to/dir/**/*')대신 사용 Dir.new('/path/to/dir')하십시오.


아니면 그냥 사용하십시오*.*
— Richard Peck


1

이 스레드의 제안 외에도 Dir.glob를 사용하여 도트 파일 (.gitignore 등)을 반환 해야하는 경우 플래그를 포함해야한다고 언급하고 싶습니다. Dir.glob("/path/to/dir/*", File::FNM_DOTMATCH) 기본적으로 Dir.entries 현재 상위 디렉토리뿐만 아니라 도트 파일도 포함합니다.

관심있는 사람에게는 실행 시간에 여기에 대한 답변이 어떻게 비교되는지 궁금합니다. 여기에 중첩 된 계층 구조에 대한 결과가 있습니다. 처음 세 가지 결과는 비재 귀적입니다.

       user     system      total        real
Dir[*]: (34900 files stepped over 100 iterations)
  0.110729   0.139060   0.249789 (  0.249961)
Dir.glob(*): (34900 files stepped over 100 iterations)
  0.112104   0.142498   0.254602 (  0.254902)
Dir.entries(): (35600 files stepped over 100 iterations)
  0.142441   0.149306   0.291747 (  0.291998)
Dir[**/*]: (2211600 files stepped over 100 iterations)
  9.399860  15.802976  25.202836 ( 25.250166)
Dir.glob(**/*): (2211600 files stepped over 100 iterations)
  9.335318  15.657782  24.993100 ( 25.006243)
Dir.entries() recursive walk: (2705500 files stepped over 100 iterations)
 14.653018  18.602017  33.255035 ( 33.268056)
Dir.glob(**/*, File::FNM_DOTMATCH): (2705500 files stepped over 100 iterations)
 12.178823  19.577409  31.756232 ( 31.767093)

이들은 다음 벤치마킹 스크립트로 생성되었습니다.

require 'benchmark'
base_dir = "/path/to/dir/"
n = 100
Benchmark.bm do |x|
  x.report("Dir[*]:") do
    i = 0
    n.times do
      i = i + Dir["#{base_dir}*"].select {|f| !File.directory? f}.length
    end
    puts " (#{i} files stepped over #{n} iterations)"
  end
  x.report("Dir.glob(*):") do
    i = 0
    n.times do
      i = i + Dir.glob("#{base_dir}/*").select {|f| !File.directory? f}.length
    end
    puts " (#{i} files stepped over #{n} iterations)"
  end
  x.report("Dir.entries():") do
    i = 0
    n.times do
      i = i + Dir.entries(base_dir).select {|f| !File.directory? File.join(base_dir, f)}.length
    end
    puts " (#{i} files stepped over #{n} iterations)"
  end
  x.report("Dir[**/*]:") do
    i = 0
    n.times do
      i = i + Dir["#{base_dir}**/*"].select {|f| !File.directory? f}.length
    end
    puts " (#{i} files stepped over #{n} iterations)"
  end
  x.report("Dir.glob(**/*):") do
    i = 0
    n.times do
      i = i + Dir.glob("#{base_dir}**/*").select {|f| !File.directory? f}.length
    end
    puts " (#{i} files stepped over #{n} iterations)"
  end
  x.report("Dir.entries() recursive walk:") do
    i = 0
    n.times do
      def walk_dir(dir, result)
        Dir.entries(dir).each do |file|
          next if file == ".." || file == "."

          path = File.join(dir, file)
          if Dir.exist?(path)
            walk_dir(path, result)
          else
            result << file
          end
        end
      end
      result = Array.new
      walk_dir(base_dir, result)
      i = i + result.length
    end
    puts " (#{i} files stepped over #{n} iterations)"
  end
  x.report("Dir.glob(**/*, File::FNM_DOTMATCH):") do
    i = 0
    n.times do
      i = i + Dir.glob("#{base_dir}**/*", File::FNM_DOTMATCH).select {|f| !File.directory? f}.length
    end
    puts " (#{i} files stepped over #{n} iterations)"
  end
end

파일 수의 차이는 Dir.entries기본적으로 숨겨진 파일 을 포함 하기 때문 입니다. Dir.entries이 경우 파일이 디렉토리인지 확인하기 위해 파일의 절대 경로를 다시 작성해야했기 때문에 시간이 조금 더 걸리지 만 재귀 적 인 경우에도 다른 옵션보다 계속 더 오래 걸리고 있습니다. 이것은 모두 OSX에서 루비 2.5.1을 사용했습니다.


1

한 가지 간단한 방법은 다음과 같습니다.

dir = './' # desired directory
files = Dir.glob(File.join(dir, '**', '*')).select{|file| File.file?(file)}

files.each do |f|
    puts f
end

0
def get_path_content(dir)
  queue = Queue.new
  result = []
  queue << dir
  until queue.empty?
    current = queue.pop
    Dir.entries(current).each { |file|
      full_name = File.join(current, file)
      if not (File.directory? full_name)
        result << full_name
      elsif file != '.' and file != '..'
          queue << full_name
      end
    }
  end
  result
end

디렉토리와 모든 하위 디렉토리에서 파일의 상대 경로를 반환합니다.


0

IRB 컨텍스트에서 다음을 사용하여 현재 디렉토리의 파일을 가져올 수 있습니다.

file_names = `ls`.split("\n")

다른 디렉토리 에서도이 작업을 수행 할 수 있습니다.

file_names = `ls ~/Documents`.split("\n")

이 솔루션은 Dir.children 명령을 지원하지 않는 오래된 루비 버전의 레거시 솔루션을 가지고 있기 때문에 저에게 효과적이었습니다.
— Ciprian Dragoe
당사 사이트를 사용함과 동시에 당사의 쿠키 정책과 개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.