फ़ाइलों को पुनरावर्ती खोजने के लिए ग्लोब () का उपयोग कैसे करें?


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'))

लेकिन यह स्पष्ट रूप से सीमित और क्लंकी है।

जवाबों:


1354

पायथन 3.5+

चूंकि आप एक नए अजगर पर हैं, इसलिए आपको मॉड्यूल pathlib.Path.rglobसे उपयोग करना चाहिए pathlib

from pathlib import Path

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

यदि आप पाथलिब का उपयोग नहीं करना चाहते हैं, तो बस उपयोग करें glob.glob, लेकिन recursiveकीवर्ड पैरामीटर में पास करना न भूलें ।

उन मामलों के लिए जहां मिलान की शुरुआत डॉट (।) के साथ होती है; वर्तमान निर्देशिका में फाइलें या यूनिक्स आधारित प्रणाली पर छिपी हुई फाइलों की तरह, os.walkनीचे दिए गए समाधान का उपयोग करें।

पुराने पायथन संस्करण

पुराने पायथन संस्करणों के लिए, 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 वर्ष से अधिक उम्र के पायथन के os.path.walk()लिए उपयोग करने के लिए थोड़ा और अधिक ध्यान देने योग्य हैos.walk()
जॉन ला रोय

20
@gnibbler मुझे पता है कि यह एक पुरानी टिप्पणी है, लेकिन मेरी टिप्पणी सिर्फ लोगों को यह बताने के लिए है कि os.path.walk()पदावनत किया गया है और अजगर 3 में हटा दिया गया है
पेड्रो कुन्हा

5
@DevC जो इस प्रश्न में पूछे गए विशिष्ट मामले में काम कर सकता है, लेकिन किसी ऐसे व्यक्ति की कल्पना करना आसान है जो इसे 'a * .c' आदि जैसे प्रश्नों के साथ उपयोग करना चाहता है, इसलिए मुझे लगता है कि यह कुछ हद तक धीमी गति से उत्तर देने के लायक है।
जोहान डाहलिन

2
क्या यह लायक है के लिए, मेरे मामले में ग्लोब के साथ 10,000+ फ़ाइलों को खोजने में os.walk की तुलना में बहुत धीमी थी, इसलिए मैं उस कारण के लिए बाद के समाधान के साथ गया था।
गॉडस्मिथ

2
अजगर 3.4 के लिए, pathlib.Path('src').glob('**/*.c')काम करना चाहिए।
CivFan

111

अन्य समाधानों के समान, लेकिन ग्लोब के बजाय fnmatch.fnmatch का उपयोग करना, क्योंकि os.walk पहले से ही फ़ाइल नाम सूचीबद्ध करता है:

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

मैंने पुनरावर्ती ग्लोबिंग के लिए ** समर्थन के लिए ग्लोब मॉड्यूल को संशोधित किया है, जैसे:

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

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

उपयोगी जब आप अपने उपयोगकर्ताओं को ** सिंटैक्स का उपयोग करने की क्षमता प्रदान करना चाहते हैं, और इस तरह ओएस.वॉक () अकेले पर्याप्त नहीं है।


2
पहला मैच देखने के बाद क्या हम इसे रोक सकते हैं? हो सकता है कि इसे हर संभव परिणाम की सूची वापस करने के बजाय एक जनरेटर के रूप में उपयोग करना संभव हो? इसके अलावा, क्या यह डीएफएस या बीएफएस है? मैं एक BFS को बहुत पसंद करूंगा, मुझे लगता है, ताकि रूट के पास मौजूद फाइलें पहले मिल जाएं। इस मॉड्यूल को बनाने और GitHub / पाइप पर उपलब्ध कराने के लिए +1।
ArtOfWarfare

14
पाइथन 3.5 में आधिकारिक ग्लोब मॉड्यूल में ** सिंटैक्स को जोड़ा गया था।
आर्टऑफवर्फ

@ArtOfWarfare ठीक है, ठीक है। यह अभी भी <3.5 के लिए उपयोगी है।
cs95

**आधिकारिक ग्लोब मॉड्यूल के साथ पुनरावर्ती ग्लोबिंग को सक्रिय करने के लिए , करें:glob(path, recursive=True)
winklerrr

68

पायथन 3.4 के साथ शुरू, एक नए पाथलिब मॉड्यूल में कक्षाओं में glob()से एक की विधि का उपयोग कर सकता है , जो वाइल्डकार्ड का समर्थन करता है । उदाहरण के लिए:Path**

from pathlib import Path

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

अद्यतन: पायथन 3.5 के साथ शुरू, वही सिंटैक्स भी समर्थित है glob.glob()


3
दरअसल, और यह पायथन 3.5 में होगा । यह पहले से ही पायथन 3.4 में होना चाहिए था, लेकिन गलती से छोड़ दिया गया था
कथा


ध्यान दें कि आप सापेक्ष पथ प्राप्त करने के लिए संयोजन में pathlib.PurePath.relative_to का भी उपयोग कर सकते हैं। अधिक संदर्भ के लिए मेरा जवाब यहां देखें ।
प्रागंरण

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
क्रिस रेडफोर्ड

@ क्रिसहेडफोर्ड, मैं इसे एक बहुत ही मामूली मुद्दे के रूप में देखता हूं। जैसा कि यह अब खड़ा है, यह "फाइल तब पैटर्न" के तर्क क्रम से मेल खाता है fnmatch.filter, जो कि एकल-तर्क के मिलान की संभावना के अनुसार लगभग उपयोगी है glob.glob
एलेक्स मार्टेली

24

अजगर के लिए> = 3.5 आप उपयोग कर सकते हैं **, recursive=True:

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

डेमो


यदि पुनरावर्ती है True, तो पैटर्न ** किसी भी फाइल और शून्य या अधिक directoriesऔर से मेल खाएगाsubdirectories । यदि पैटर्न ए os.sep, केवल निर्देशिका और subdirectoriesमैच के बाद है।


2
यह pathlib.Path ('./ पथ /') से बेहतर काम करता है। ग्लोब (' * / ') क्योंकि यह 0 के आकार के साथ फ़ोल्डर में भी है
चार्ल्स वॉकर

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शैली के पैटर्न की आवश्यकता है , तो आप एलेक्स और ब्रूनो के उदाहरण और उपयोग का अनुसरण कर सकते हैं 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। मैंने फोटोरेक को चलाया और 4579 निर्देशिकाओं को 2.2 मिलियन फाइलों के भीतर बरामद किया, जिसमें बहुत अधिक विविधताएँ थीं। नीचे दी गई स्क्रिप्ट मैं मिनटों के भीतर 50133 फ़ाइलों के हविन .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)

यहाँ भी @ टेलिनेट की संबंधित पोस्ट देखें और इसी तरह की पोस्ट कहीं और।


5

जोहान और ब्रूनो कहा गया न्यूनतम आवश्यकता पर उत्कृष्ट समाधान प्रदान करते हैं। मैंने अभी फॉर्मिक जारी किया है जो चींटी फाइलसेट और ग्लब्स को लागू करता है जो इसे और अधिक जटिल परिदृश्यों को संभाल सकता है। आपकी आवश्यकता का कार्यान्वयन है:

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

1
औपचारिक छोड़ दिया प्रतीत होता है ?! और यह अजगर 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

सिर्फ ग्लोब मॉड्यूल का उपयोग करके इसे करने का दूसरा तरीका। बस एक प्रारंभिक आधार निर्देशिका और मिलान करने के लिए एक पैटर्न के साथ 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

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 या चलने का उपयोग नहीं किया

#!/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

अजगर 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

यह पायथन 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

यहाँ मेरी समाधान के लिए खोज करने के लिए सूची समझ का उपयोग कर एकाधिक फ़ाइल एक्सटेंशन रिकर्सिवली एक निर्देशिका और सभी उप-निर्देशिकाओं के:

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

मैंने इस पोस्टिंग में शीर्ष उत्तर को संशोधित किया है .. और हाल ही में इस स्क्रिप्ट को बनाया है जो किसी दिए गए डायरेक्टरी (सर्चडिर) में सभी फाइलों के माध्यम से लूप करेगा और इसके तहत उप-निर्देशिका ... और प्रिंट नाम, रूटडिअर, संशोधित / निर्माण तिथि और प्रिंट करता है, और आकार।

आशा है कि यह किसी की मदद करता है ... और वे निर्देशिका को चला सकते हैं और फाइलइन्फो प्राप्त कर सकते हैं।

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.translateएक ग्लोब-स्टाइल पैटर्न को एक नियमित अभिव्यक्ति में बदलने के लिए उपयोग करता है, जो तब निर्देशिका को चलते समय मिली प्रत्येक फ़ाइल के पूर्ण पथ के विरुद्ध मेल खाता है।

re.IGNORECASEवैकल्पिक है, लेकिन विंडोज पर वांछनीय है क्योंकि फाइल सिस्टम स्वयं केस-संवेदी नहीं है। (मैं regex संकलन परेशान नहीं किया क्योंकि डॉक्स यह आंतरिक रूप से कैश किया जाना चाहिए संकेत मिलता है।)

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

मुझे अजगर 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/**/*.cग्लोबस्टार विकल्प सक्षम होने पर ही काम करता है ( shopt -s globstar) - विवरण के लिए यह उत्तर देखें।
रोमन
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.