glob ()를 사용하여 재귀 적으로 파일을 찾는 방법은 무엇입니까?


738

이것이 내가 가진 것입니다 :

glob(os.path.join('src','*.c'))

src의 하위 폴더를 검색하고 싶습니다. 이와 같은 것이 효과가 있습니다.

glob(os.path.join('src','*.c'))
glob(os.path.join('src','*','*.c'))
glob(os.path.join('src','*','*','*.c'))
glob(os.path.join('src','*','*','*','*.c'))

그러나 이것은 분명히 제한적이고 어수선합니다.

답변:


1355

파이썬 3.5 이상

새로운 파이썬을 사용 pathlib.Path.rglob하고 있으므로 pathlib모듈 에서 사용해야 합니다.

from pathlib import Path

for path in Path('src').rglob('*.c'):
    print(path.name)

pathlib를 사용하지 않으려면을 사용 glob.glob하지만 recursive키워드 매개 변수 를 전달하는 것을 잊지 마십시오 .

일치하는 파일이 점 (.)으로 시작하는 경우 현재 디렉토리의 파일 또는 Unix 기반 시스템의 숨겨진 파일과 같이 os.walk아래 솔루션을 사용하십시오 .

이전 파이썬 버전

이전 Python 버전의 os.walk경우 디렉토리를 재귀 적으로 탐색 fnmatch.filter하고 간단한 표현식과 일치시키는 데 사용하십시오.

import fnmatch
import os

matches = []
for root, dirnames, filenames in os.walk('src'):
    for filename in fnmatch.filter(filenames, '*.c'):
        matches.append(os.path.join(root, filename))

3
2.2보다 오래된 Python의 경우 다음보다 os.path.walk()약간 더 사용하기가 os.walk()
쉽지

20
@gnibbler 나는 그것이 오래된 의견이라는 것을 알고 있지만, 나의 의견은 사람들에게 os.path.walk()더 이상 사용되지 않으며 파이썬 3에서 제거되었다는 것을 알리는 것 입니다.
Pedro Cunha

5
@DevC는이 질문에서 특정 사례에서 작동 할 수 있지만 'a * .c'와 같은 쿼리에 사용하려는 사람을 상상하기 쉽습니다. 따라서 현재 느린 응답을 유지하는 것이 좋습니다.
Johan Dahlin

2
가치가있는 경우, 내 경우에는 glob가있는 10,000 + 파일을 찾는 것이 os.walk보다 훨씬 느리므로 그 이유로 후자의 솔루션을 사용했습니다.
대장장이 September

2
파이썬 3.4의 경우 pathlib.Path('src').glob('**/*.c')작동합니다.
CivFan

111

os.walk가 이미 파일 이름을 나열 했으므로 다른 솔루션과 유사하지만 glob 대신 fnmatch.fnmatch를 사용합니다.

import os, fnmatch


def find_files(directory, pattern):
    for root, dirs, files in os.walk(directory):
        for basename in files:
            if fnmatch.fnmatch(basename, pattern):
                filename = os.path.join(root, basename)
                yield filename


for filename in find_files('src', '*.c'):
    print 'Found C source:', filename

또한 생성기를 사용하면 모든 파일을 찾아서 처리하는 대신 발견 된대로 각 파일 처리 할 수 ​​있습니다.


3
: 1 - 라이너 재미 있기 때문에reduce(lambda x, y: x+y, map(lambda (r,_,x):map(lambda f: r+'/'+f, filter(lambda f: fnmatch.fnmatch(f, pattern), x)), os.walk('src/webapp/test_scripts')))
njzk2

1
@ njzk2(os.path.join(root,filename) for root, dirs, files in os.walk(directory) for filename in files if fnmatch.fnmatch(filename, pattern))
Baldrickk

73

재귀 globbing을 지원하기 위해 glob 모듈을 수정했습니다. 예 :

>>> import glob2
>>> all_header_files = glob2.glob('src/**/*.c')

https://github.com/miracle2k/python-glob2/

** 구문을 사용할 수있는 기능을 사용자에게 제공 할 때 유용하므로 os.walk ()만으로는 충분하지 않습니다.


2
첫 번째 일치를 찾은 후에이 중지를 할 수 있습니까? 어쩌면 가능한 모든 결과 목록을 반환하지 않고 생성기로 사용할 수 있습니까? 또한 이것이 DFS입니까 아니면 BFS입니까? 루트에 가까운 파일을 먼저 찾을 수 있도록 BFS를 선호합니다. 이 모듈을 만들고 GitHub / pip에서 제공하는 +1
ArtOfWarfare 18

14
** 구문은 Python 3.5의 공식 glob 모듈에 추가되었습니다.
ArtOfWarfare

@ArtOfWarfare 좋아, 좋아. 이것은 여전히 ​​<3.5에 유용합니다.
cs95

1
**공식 glob 모듈을 사용하여 재귀 globbing을 활성화하려면 다음 과 같이하십시오.glob(path, recursive=True)
winklerrr

68

Python 3.4부터는 와일드 카드 를 지원 하는 새로운 pathlib 모듈 에서 클래스 glob()중 하나의 메소드를 사용할 수 있습니다 . 예를 들면 다음과 같습니다.Path**

from pathlib import Path

for file_path in Path('src').glob('**/*.c'):
    print(file_path) # do whatever you need with these files

업데이트 : Python 3.5부터는 동일한 구문이 지원됩니다 glob.glob().


3
실제로, 그것은 파이썬 3.5에있을 것입니다 . 파이썬 3.4에서는 이미 그렇게되었지만 실수생략되었습니다 .
taleinat


pathlib.PurePath.relative_to 를 조합하여 상대 경로를 얻을 수도 있습니다 . 자세한 내용은 여기 내 답변을 참조하십시오 .
pjgranahan

40
import os
import fnmatch


def recursive_glob(treeroot, pattern):
    results = []
    for base, dirs, files in os.walk(treeroot):
        goodfiles = fnmatch.filter(files, pattern)
        results.extend(os.path.join(base, f) for f in goodfiles)
    return results

fnmatch와 정확히 동일한 패턴을 제공 glob하므로 glob.glob매우 가까운 의미론을 대체 할 수 있습니다. IOW의 대체 버전 인 반복 버전 (예 : 생성기) glob.iglob은 사소한 조정입니다 ( 단일 결과 목록을 반환하는 yield대신 중간 결과 만 extend표시).


1
recursive_glob(pattern, treeroot='.')편집 할 때 제안한대로 사용하는 것에 대해 어떻게 생각 하십니까? 이러한 방식으로 예를 들어 recursive_glob('*.txt')의 구문과 직관적으로 일치 하도록 호출 할 수 있습니다 glob.
Chris Redford

@ChrisRedford, 나는 어느 쪽이든 아주 사소한 문제로 본다. 이제는 "files then pattern"인수 순서 fnmatch.filter와 일치하는데, 이는 single-argument 일치 가능성만큼이나 유용합니다 glob.glob.
Alex Martelli

25

파이썬> = 3.5 사용할 수있는 **, recursive=True:

import glob
for x in glob.glob('path/**/*.c', recursive=True):
    print(x)

데모


재귀 인 경우 True, 패턴은 ** 모든 파일과 0 개 이상의 일치 directoriessubdirectories . 패턴 다음에가 오는 os.sep경우 디렉토리 만 subdirectories일치합니다.


2
pathlib.Path ( './ path /'). glob ( ' * / ')보다 크기가 0 인 폴더에서도 작동합니다.
Charles Walker

20

os.walk기준과 일치하는 파일 이름을 수집하는 데 사용하려고 합니다. 예를 들면 다음과 같습니다.

import os
cfiles = []
for root, dirs, files in os.walk('src'):
  for file in files:
    if file.endswith('.c'):
      cfiles.append(os.path.join(root, file))

15

다음은 중첩 목록 이해 os.walk및 간단한 접미사가 일치 하는 솔루션 입니다 glob.

import os
cfiles = [os.path.join(root, filename)
          for root, dirnames, filenames in os.walk('src')
          for filename in filenames if filename.endswith('.c')]

하나의 라이너로 압축 할 수 있습니다.

import os;cfiles=[os.path.join(r,f) for r,d,fs in os.walk('src') for f in fs if f.endswith('.c')]

또는 함수로 일반화되었습니다.

import os

def recursive_glob(rootdir='.', suffix=''):
    return [os.path.join(looproot, filename)
            for looproot, _, filenames in os.walk(rootdir)
            for filename in filenames if filename.endswith(suffix)]

cfiles = recursive_glob('src', '.c')

glob스타일 패턴 이 필요한 경우 Alex와 Bruno의 예를 따라 다음을 사용할 수 있습니다 fnmatch.

import fnmatch
import os

def recursive_glob(rootdir='.', pattern='*'):
    return [os.path.join(looproot, filename)
            for looproot, _, filenames in os.walk(rootdir)
            for filename in filenames
            if fnmatch.fnmatch(filename, pattern)]

cfiles = recursive_glob('src', '*.c')

7

최근에 확장자가 .jpg 인 사진을 복구해야했습니다. 나는 photorec을 실행하고 엄청나게 다양한 확장자를 가진 220 만 개의 파일을 220 만 개의 파일로 복구했습니다. 아래 스크립트를 사용하면 몇 분 안에 50133 파일 havin .jpg 확장자를 선택할 수있었습니다

#!/usr/binenv python2.7

import glob
import shutil
import os

src_dir = "/home/mustafa/Masaüstü/yedek"
dst_dir = "/home/mustafa/Genel/media"
for mediafile in glob.iglob(os.path.join(src_dir, "*", "*.jpg")): #"*" is for subdirectory
    shutil.copy(mediafile, dst_dir)

7

고려하십시오 pathlib.rglob().

이것은 주어진 상대 패턴 앞에 추가하여 호출 Path.glob()하는 것과 같습니다 "**/".

import pathlib


for p in pathlib.Path("src").rglob("*.c"):
    print(p)

@taleinat의 관련 게시물 here 및 다른 곳에서도 비슷한 게시물을 참조하십시오 .


5

Johan과 Bruno는 명시된 최소 요구 사항에 대한 탁월한 솔루션을 제공합니다. 방금 이 복잡한 시나리오를 처리 할 수있는 Ant FileSet 및 Glob 을 구현하는 Formic 을 출시했습니다 . 요구 사항의 구현은 다음과 같습니다.

import formic
fileset = formic.FileSet(include="/src/**/*.c")
for file_name in fileset.qualified_files():
    print file_name

1
포름은 버린 것 같아?! 그리고 그것은 Python 3 ( bitbucket.org/aviser/formic/issue/12/support-python-3 )을 지원하지 않습니다
blueyed

5

다른 답변을 기반으로 이것은 현재 작동중인 구현이며 루트 디렉토리에서 중첩 된 xml 파일을 검색합니다.

files = []
for root, dirnames, filenames in os.walk(myDir):
    files.extend(glob.glob(root + "/*.xml"))

나는 정말로 파이썬과 재미있다 :)


3

glob 모듈을 사용하는 또 다른 방법입니다. 시작 기본 디렉토리와 일치하는 패턴으로 rglob 메소드를 시드하면 일치하는 파일 이름 목록이 리턴됩니다.

import glob
import os

def _getDirs(base):
    return [x for x in glob.iglob(os.path.join( base, '*')) if os.path.isdir(x) ]

def rglob(base, pattern):
    list = []
    list.extend(glob.glob(os.path.join(base,pattern)))
    dirs = _getDirs(base)
    if len(dirs):
        for d in dirs:
            list.extend(rglob(os.path.join(base,d), pattern))
    return list

3

파이썬 3.5 이상

import glob

#file_names_array = glob.glob('path/*.c', recursive=True)
#above works for files directly at path/ as guided by NeStack

#updated version
file_names_array = glob.glob('path/**/*.c', recursive=True)

또한 당신은 필요할 수 있습니다

for full_path_in_src in  file_names_array:
    print (full_path_in_src ) # be like 'abc/xyz.c'
    #Full system path of this would be like => 'path till src/abc/xyz.c'

3
첫 번째 코드 줄은 하위 디렉토리를 조사하는 데 작동하지 않습니다. 그러나 당신이 그것을 확장하면 /**그것은 나를 위해 다음과 같이 작동합니다 :file_names_array = glob.glob('src/**/*.c', recursive=True)
NeStack

2

또는 목록 이해와 함께 :

 >>> base = r"c:\User\xtofl"
 >>> binfiles = [ os.path.join(base,f) 
            for base, _, files in os.walk(root) 
            for f in files if f.endswith(".jpg") ] 

2

방금 만들었습니다. 파일과 디렉토리를 계층 적으로 인쇄합니다.

그러나 나는 fnmatch 또는 walk를 사용하지 않았습니다.

#!/usr/bin/python

import os,glob,sys

def dirlist(path, c = 1):

        for i in glob.glob(os.path.join(path, "*")):
                if os.path.isfile(i):
                        filepath, filename = os.path.split(i)
                        print '----' *c + filename

                elif os.path.isdir(i):
                        dirname = os.path.basename(i)
                        print '----' *c + dirname
                        c+=1
                        dirlist(i,c)
                        c-=1


path = os.path.normpath(sys.argv[1])
print(os.path.basename(path))
dirlist(path)

2

그것은 fnmatch 또는 정규 표현식을 사용합니다.

import fnmatch, os

def filepaths(directory, pattern):
    for root, dirs, files in os.walk(directory):
        for basename in files:
            try:
                matched = pattern.match(basename)
            except AttributeError:
                matched = fnmatch.fnmatch(basename, pattern)
            if matched:
                yield os.path.join(root, basename)

# usage
if __name__ == '__main__':
    from pprint import pprint as pp
    import re
    path = r'/Users/hipertracker/app/myapp'
    pp([x for x in filepaths(path, re.compile(r'.*\.py$'))])
    pp([x for x in filepaths(path, '*.py')])

2

제안 된 답변 외에도 게으른 생성 및 목록 이해 마법 으로이 작업을 수행 할 수 있습니다.

import os, glob, itertools

results = itertools.chain.from_iterable(glob.iglob(os.path.join(root,'*.c'))
                                               for root, dirs, files in os.walk('src'))

for f in results: print(f)

한 줄에 맞추고 메모리에 불필요한 목록을 피하는 것 외에도 ** 연산자와 비슷한 방식으로 사용할 수있는 부작용이 있습니다. 예를 들어 os.path.join(root, 'some/path/*.c')모든 .c 파일을 모두 가져 오기 위해 사용할 수 있습니다 이 구조를 가진 src의 하위 디렉토리.


2

이것은 Python 2.7에서 작동하는 코드입니다. 개발자 작업의 일환으로 live-appName.properties로 표시된 구성 파일을 appName.properties로 이동시키는 스크립트를 작성해야했습니다. live-appName.xml과 같은 다른 확장 파일이있을 수 있습니다.

아래는 이것에 대한 작업 코드입니다.이 디렉토리는 주어진 디렉토리 (중첩 수준)에서 파일을 찾은 다음 필요한 파일 이름으로 이름을 변경 (이동)합니다.

def flipProperties(searchDir):
   print "Flipping properties to point to live DB"
   for root, dirnames, filenames in os.walk(searchDir):
      for filename in fnmatch.filter(filenames, 'live-*.*'):
        targetFileName = os.path.join(root, filename.split("live-")[1])
        print "File "+ os.path.join(root, filename) + "will be moved to " + targetFileName
        shutil.move(os.path.join(root, filename), targetFileName)

이 함수는 기본 스크립트에서 호출됩니다

flipProperties(searchDir)

이것이 비슷한 문제로 어려움을 겪고있는 누군가를 돕기를 바랍니다.


1

fnmatch 없이 Johan Dahlin의 답변을 단순화 한 버전입니다 .

import os

matches = []
for root, dirnames, filenames in os.walk('src'):
  matches += [os.path.join(root, f) for f in filenames if f[-2:] == '.c']

1

다음은 디렉토리와 모든 하위 디렉토리에서 재귀 적 으로 여러 파일 확장자 를 검색하기 위해 목록 이해를 사용하는 솔루션입니다 .

import os, glob

def _globrec(path, *exts):
""" Glob recursively a directory and all subdirectories for multiple file extensions 
    Note: Glob is case-insensitive, i. e. for '\*.jpg' you will get files ending
    with .jpg and .JPG

    Parameters
    ----------
    path : str
        A directory name
    exts : tuple
        File extensions to glob for

    Returns
    -------
    files : list
        list of files matching extensions in exts in path and subfolders

    """
    dirs = [a[0] for a in os.walk(path)]
    f_filter = [d+e for d in dirs for e in exts]    
    return [f for files in [glob.iglob(files) for files in f_filter] for f in files]

my_pictures = _globrec(r'C:\Temp', '\*.jpg','\*.bmp','\*.png','\*.gif')
for f in my_pictures:
    print f

0
import sys, os, glob

dir_list = ["c:\\books\\heap"]

while len(dir_list) > 0:
    cur_dir = dir_list[0]
    del dir_list[0]
    list_of_files = glob.glob(cur_dir+'\\*')
    for book in list_of_files:
        if os.path.isfile(book):
            print(book)
        else:
            dir_list.append(book)

0

나는이 게시물의 최상위 답변을 수정했습니다. 최근에는 주어진 디렉토리 (searchdir) 및 그 아래의 하위 디렉토리에있는 모든 파일을 반복하고 파일 이름, rootdir, 수정 / 생성 날짜 및 크기.

이것이 누군가에게 도움이되기를 바랍니다 ... 그들은 디렉토리를 걷고 파일 정보를 얻을 수 있습니다.

import time
import fnmatch
import os

def fileinfo(file):
    filename = os.path.basename(file)
    rootdir = os.path.dirname(file)
    lastmod = time.ctime(os.path.getmtime(file))
    creation = time.ctime(os.path.getctime(file))
    filesize = os.path.getsize(file)

    print "%s**\t%s\t%s\t%s\t%s" % (rootdir, filename, lastmod, creation, filesize)

searchdir = r'D:\Your\Directory\Root'
matches = []

for root, dirnames, filenames in os.walk(searchdir):
    ##  for filename in fnmatch.filter(filenames, '*.c'):
    for filename in filenames:
        ##      matches.append(os.path.join(root, filename))
        ##print matches
        fileinfo(os.path.join(root, filename))

0

기본 파일 이름뿐만 아니라 전체 경로와 패턴을 일치시키는 솔루션이 있습니다.

사용합니다 fnmatch.translateglob 스타일 패턴을 정규식으로 변환하는 되며, 이는 디렉토리를 걷는 동안 발견 된 각 파일의 전체 경로와 일치합니다.

re.IGNORECASE파일 시스템 자체는 대소 문자를 구분하지 않으므로 Windows에서는 선택 사항이지만 Windows에서는 바람직합니다. (문서가 내부적으로 캐시되어야 함을 나타 내기 때문에 정규식을 컴파일하는 것을 귀찮게하지 않았습니다.)

import fnmatch
import os
import re

def findfiles(dir, pattern):
    patternregex = fnmatch.translate(pattern)
    for root, dirs, files in os.walk(dir):
        for basename in files:
            filename = os.path.join(root, basename)
            if re.search(patternregex, filename, re.IGNORECASE):
                yield filename

0

큰 디렉토리에서 빠르게 작동 하는 python 2.x 솔루션이 필요했습니다 . 나는 이것으로 끝났다.

import subprocess
foundfiles= subprocess.check_output("ls src/*.c src/**/*.c", shell=True)
for foundfile in foundfiles.splitlines():
    print foundfile

ls일치하는 파일을 찾지 못하면 예외 처리가 필요할 수 있습니다 .


ls src/**/*.cglobstar 옵션이 활성화 된 경우에만 작동 한다는 것을 깨달았습니다 ( shopt -s globstar)-자세한 내용은 이 답변 을 참조하십시오.
Roman
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.