glob exclude шаблон

105

У меня есть каталог с кучей файлов внутри: eee2314, asd3442... и eph.

Я хочу , чтобы исключить все файлы , которые начинаются с ephс globфункцией.

Как я могу это сделать?

Анастасиос Андронидис
источник

Ответы:

148

Шаблонные правила для glob не являются регулярными выражениями. Вместо этого они следуют стандартным правилам расширения пути Unix. Есть только несколько специальных символов: два разных символа подстановки и диапазоны символов поддерживаются [from glob ].

Таким образом, вы можете исключить некоторые файлы с шаблонами.
Например, чтобы исключить файлы манифестов (файлы, начинающиеся с _) с помощью glob, вы можете использовать:

files = glob.glob('files_path/[!_]*')
Кенли
источник
10
Это должно быть в официальной документации, пожалуйста, добавьте это в docs.python.org/3.5/library/glob.html#glob.glob
Виталий Зданевич
6
Обратите внимание, что шаблоны глобуса не могут напрямую выполнить требование, установленное OP: исключать только файлы, которые начинаются с, ephно могут начинаться с чего-либо еще. [!e][!p][!h]отфильтрует файлы, которые начинаются, eeeнапример, с.
Мартейн Питерс
60

Вы можете вычесть наборы:

set(glob("*")) - set(glob("eph*"))
нейтринус
источник
3
Действительно интересное решение! Но мой случай будет очень медленным, чтобы прочитать дважды. Также, если содержимое папки в сетевом каталоге велико, это снова будет медленным. Но в любом случае действительно пригодится.
Анастасиос Андронидис
Ваша операционная система должна кэшировать запросы файловой системы, так что не так уж и плохо :)
Neutrinus
Пробовал сам, я только что получил TypeError: неподдерживаемые типы операндов для -: 'list' и 'list'
Том Басби
1
@TomBusby Попробуйте преобразовать их в наборы: set(glob("*")) - set(glob("eph*")) (и обратите внимание * в конце "eph *")
Jaszczur
2
В качестве примечания, glob возвращает списки, а не наборы, но этот вид операции работает только с наборами, поэтому нейтринус использовал его. Если вам нужно, чтобы он оставался списком, просто оберните всю операцию в гипс:list(set(glob("*")) - set(glob("eph")))
Натан Смит,
48

Вы не можете исключить шаблоны с помощью globфункции, глобусы допускают только шаблоны включения . Синтаксис подстановки очень ограничен (даже [!..]класс символов должен соответствовать символу, поэтому это шаблон включения для каждого символа, не входящего в класс).

Вам нужно будет выполнить собственную фильтрацию; понимание списка обычно хорошо работает здесь:

files = [fn for fn in glob('somepath/*.txt') 
         if not os.path.basename(fn).startswith('eph')]
Мартейн Питерс
источник
3
Используйте iglobздесь, чтобы не хранить полный список в памяти
Евгений Панков
3
@Hardex: внутренне, все равноiglob создает списки ; все, что вы делаете, это лениво оцениваете фильтр. Это не поможет уменьшить объем памяти.
Мартин Питерс
@Hardex: если вы используете глобус в имени каталога, тогда у вас будет точка, тогда os.listdir()в памяти сохраняется не более одного результата при итерации. Но somepath/*.txtон должен прочитать все имена файлов в одном каталоге в памяти, а затем сократить этот список до только тех, которые соответствуют.
Мартин Питерс
Вы правы, это не так уж важно, но в наличии CPython, glob.glob(x) = list(glob.iglob(x)). Небольшие накладные расходы, но все же полезно знать.
Евгений Панков
Разве это не повторяется дважды? Один раз через файлы получить список, а второй через сам список? Если да, то нельзя ли сделать это за одну итерацию?
Ридхуваршан
6

Поздно в игре, но вы также можете просто применить питон filterк результату glob:

files = glob.iglob('your_path_here')
files_i_care_about = filter(lambda x: not x.startswith("eph"), files)

или замена лямбды на соответствующий поиск по регулярному выражению и т. д.

РЕДАКТИРОВАТЬ: Я только что понял, что если вы используете полные пути, это startswithне сработает, поэтому вам понадобится регулярное выражение

In [10]: a
Out[10]: ['/some/path/foo', 'some/path/bar', 'some/path/eph_thing']

In [11]: filter(lambda x: not re.search('/eph', x), a)
Out[11]: ['/some/path/foo', 'some/path/bar']
К. Рафаэль
источник
5

Как насчет пропуска конкретного файла при итерации по всем файлам в папке! Код ниже пропустит все файлы Excel, которые начинаются с 'eph'.

import glob
import re
for file in glob.glob('*.xlsx'):
    if re.match('eph.*\.xlsx',file):
        continue
    else:
        #do your stuff here
        print(file)

Таким образом, вы можете использовать более сложные шаблоны регулярных выражений для включения / исключения определенного набора файлов в папке.

Азхар Ансари
источник
5

Сравнить с glob, рекомендую pathlib, фильтровать по одному шаблону очень просто.

from pathlib import Path

p = Path(YOUR_PATH)
filtered = [x for x in p.glob("**/*") if not x.name.startswith("eph")]

и если вы хотите отфильтровать более сложный шаблон, вы можете определить функцию для этого, например:

def not_in_pattern(x):
    return (not x.name.startswith("eph")) and not x.name.startswith("epi")


filtered = [x for x in p.glob("**/*") if not_in_pattern(x)]

используя этот код, вы можете фильтровать все файлы, которые начинаются с ephили начинаются с epi.

Скотт Мин
источник
4

В более общем плане, чтобы исключить файлы, которые не соответствуют некоторому регулярному выражению оболочки, вы можете использовать module fnmatch:

import fnmatch

file_list = glob('somepath')    
for ind, ii in enumerate(file_list):
    if not fnmatch.fnmatch(ii, 'bash_regexp_with_exclude'):
        file_list.pop(ind)

Приведенное выше сначала сгенерирует список по заданному пути, а затем выскочит файлы, которые не удовлетворяют регулярному выражению с желаемым ограничением.

Лорд Генри Уоттон
источник
0

Как упоминалось в принятом ответе, вы не можете исключить шаблоны с помощью glob, поэтому ниже приведен метод фильтрации вашего результата glob.

Принятый ответ, вероятно, является лучшим питоническим способом сделать что-то, но если вы думаете, что понимание списка выглядит немного уродливо и все равно хотите сделать свой код максимально numpythonic (как я), тогда вы можете это сделать (но обратите внимание, что это, вероятно, менее эффективно чем метод понимания списка):

import glob

data_files = glob.glob("path_to_files/*.fits")

light_files = np.setdiff1d( data_files, glob.glob("*BIAS*"))
light_files = np.setdiff1d(light_files, glob.glob("*FLAT*"))

(В моем случае у меня было несколько кадров изображений, кадров смещения и плоских кадров в одном каталоге, и мне просто нужны были кадры изображений)

Райан Фарбер
источник
0

Если положение символа не важно, например, чтобы исключить файлы манифестов (где бы он ни находился _) с помощью операцийglob и re- регулярных выражений , вы можете использовать:

import glob
import re
for file in glob.glob('*.txt'):
    if re.match(r'.*\_.*', file):
        continue
    else:
        print(file)

Или более изящным способом - list comprehension

filtered = [f for f in glob.glob('*.txt') if not re.match(r'.*\_.*', f)]

for mach in filtered:
    print(mach)
Милован Томашевич
источник
-1

Вы можете использовать следующий метод:

# Get all the files
allFiles = glob.glob("*")
# Files starting with eph
ephFiles = glob.glob("eph*")
# Files which doesnt start with eph
noephFiles = []
for file in allFiles:
    if file not in ephFiles:
        noephFiles.append(file)
# noepchFiles has all the file which doesnt start with eph.

Thank you.  
KK2491
источник