glob wyklucza wzorzec


110

Mam katalog z bandą plików wewnątrz: eee2314, asd3442... a eph.

Chcę wykluczyć wszystkie pliki, które zaczynają ephsię od globfunkcji.

Jak mogę to zrobić?

Odpowiedzi:


162

Reguły wzorców dla glob nie są wyrażeniami regularnymi. Zamiast tego stosują się do standardowych reguł rozwijania ścieżek w systemie Unix. Jest tylko kilka znaków specjalnych: dwa różne symbole wieloznaczne i obsługiwane są zakresy znaków [z pymotw: glob - dopasowanie wzorca nazwy pliku ].

Możesz więc wykluczyć niektóre pliki z wzorami.
Na przykład, aby wykluczyć pliki manifestów (pliki zaczynające się od _) z glob, możesz użyć:

files = glob.glob('files_path/[!_]*')

10
To musi znajdować się w oficjalnej dokumentacji, niech ktoś doda to do docs.python.org/3.5/library/glob.html#glob.glob
Witalij Zdanevich

8
Zauważ, że wzorce glob nie mogą bezpośrednio spełnić wymagania określonego przez OP: wykluczać tylko pliki, które zaczynają się od, ephale mogą zaczynać się od czegoś innego. [!e][!p][!h]odfiltruje pliki zaczynające się eeena przykład od.
Martijn Pieters

60

Możesz odliczyć zestawy:

set(glob("*")) - set(glob("eph*"))

4
Naprawdę ciekawe rozwiązanie! Ale mój przypadek będzie bardzo wolny, aby przeczytać dwukrotnie. Również jeśli zawartość folderu w katalogu sieciowym jest duża, znowu będzie wolna. Ale w każdym razie naprawdę przydatne.
Anastasios Andronidis

Twój system operacyjny powinien buforować żądania systemu plików, więc nie jest tak źle :)
neutrinus

Wypróbowałem to sam, właśnie dostałem TypeError: nieobsługiwane typy operandów dla -: 'list' i 'list'
Tom Busby

1
@TomBusby Spróbuj przekonwertować je na zestawy: set(glob("*")) - set(glob("eph*")) (i zauważ * na końcu „eph *”)
Jaszczur

2
Tak na marginesie, glob zwraca listy, a nie zbiory, ale ten rodzaj operacji działa tylko na zbiorach, stąd dlaczego neutrinus to rzuca. Jeśli chcesz, aby pozostała listą, po prostu zapakuj całą operację w obsadę:list(set(glob("*")) - set(glob("eph")))
Nathan Smith

48

Nie możesz wykluczyć wzorców za pomocą globfunkcji, globy pozwalają tylko na włączanie wzorców. Składnia globbingu jest bardzo ograniczona (nawet [!..]klasa znaków musi pasować do znaku, więc jest to wzorzec włączenia dla każdego znaku, którego nie ma w klasie).

Będziesz musiał wykonać własne filtrowanie; rozumienie listy zwykle dobrze działa tutaj:

files = [fn for fn in glob('somepath/*.txt') 
         if not os.path.basename(fn).startswith('eph')]

3
Użyj iglobtutaj, aby uniknąć przechowywania pełnej listy w pamięci
Eugene Pankov

3
@Hardex: wewnętrznie i takiglob tworzy listy ; wszystko co robisz to leniwie oceniasz filtr. Nie pomoże to w zmniejszeniu zużycia pamięci.
Martijn Pieters

@Hardex: jeśli użyjesz globu w nazwie katalogu, będziesz miał punkt, wtedy co najwyżej jeden os.listdir()wynik jest przechowywany w pamięci podczas iteracji. Ale somepath/*.txtmusi czytać wszystkie nazwy plików w jednym katalogu w pamięci, a następnie zredukować tę listę do tylko tych, które pasują.
Martijn Pieters

masz rację, to nie jest takie ważne, ale w stanie CPython, glob.glob(x) = list(glob.iglob(x)). Niewielkie koszty, ale dobrze wiedzieć.
Eugene Pankov,

Czy to nie powtarza się dwukrotnie? Raz przez pliki, aby uzyskać listę, a drugi przez samą listę? Jeśli tak, czy nie można tego zrobić w jednej iteracji?
Ridhuvarshan

6

Spóźniony do gry, ale alternatywnie możesz po prostu zastosować Pythona filterdo wyniku glob:

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

lub zastąpienie lambdy odpowiednim wyszukiwaniem wyrażeń regularnych itp.

EDYCJA: Właśnie zdałem sobie sprawę, że jeśli używasz pełnych ścieżek startswith, nie zadziała, więc potrzebujesz wyrażenia regularnego

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

Co powiesz na pominięcie konkretnego pliku podczas iteracji po wszystkich plikach w folderze! Poniższy kod pomija wszystkie pliki Excela zaczynające się od „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)

W ten sposób możesz użyć bardziej złożonych wzorców regex, aby uwzględnić / wykluczyć określony zestaw plików w folderze.


5

Porównaj z glob, polecam pathlib, filtr jeden wzorzec jest bardzo prosty.

from pathlib import Path

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

a jeśli chcesz filtrować bardziej złożony wzorzec, możesz zdefiniować funkcję, która to zrobi, tak jak:

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

użyj tego kodu, możesz filtrować wszystkie pliki, które zaczynają się od ephlub zaczynają się od epi.


4

Bardziej ogólnie, aby wykluczyć pliki, które nie są zgodne z niektórymi wyrażeniami regularnymi powłoki, możesz użyć modułu 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)

Powyższe najpierw wygeneruje listę z podanej ścieżki, a następnie wyskoczy pliki, które nie spełnią wyrażenia regularnego z żądanym ograniczeniem.


0

Jak wspomniano w akceptowanej odpowiedzi, nie możesz wykluczyć wzorców za pomocą glob, więc poniżej przedstawiono metodę filtrowania wyniku glob.

Przyjęta odpowiedź jest prawdopodobnie najlepszym Pythonowym sposobem robienia rzeczy, ale jeśli uważasz, że listy składane wyglądają trochę brzydko i chcesz, aby Twój kod i tak był maksymalnie numpythonic (tak jak ja), możesz to zrobić (ale pamiętaj, że jest to prawdopodobnie mniej wydajne niż metoda rozumienia listy):

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*"))

(W moim przypadku miałem kilka ramek obrazów, ramek odchylenia i płaskich ramek w jednym katalogu i chciałem tylko ramki obrazów)


0

Jeśli pozycja znaku nie jest ważna, to znaczy na przykład, aby wykluczyć pliki manifestów (gdziekolwiek zostanie znaleziony _) za pomocą globi re- operacji wyrażeń regularnych , możesz użyć:

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

Lub w bardziej elegancki sposób - list comprehension

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

for mach in filtered:
    print(mach)

-1

Możesz użyć poniższej metody:

# 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.  
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.