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ć?

Anastasios Andronidis
źródło

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/[!_]*')
Kenly
źródło
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*"))
neutrinus
źródło
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')]
Martijn Pieters
źródło
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']
K Raphael
źródło
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.

Azhar Ansari
źródło
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.

Scott Ming
źródło
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.

Lord Henry Wotton
źródło
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)

Ryan Farber
źródło
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)
Milovan Tomašević
źródło
-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.  
KK2491
źródło