Glob-Ausschlussmuster

95

Ich habe ein Verzeichnis mit einer Reihe von Dateien : eee2314, asd3442... und eph.

Ich möchte alle Dateien ausschließen, die ephmit der globFunktion beginnen.

Wie kann ich es tun?

Anastasios Andronidis
quelle

Antworten:

134

Die Musterregeln für glob sind keine regulären Ausdrücke. Stattdessen folgen sie den Standardregeln für die Unix-Pfaderweiterung. Es gibt nur wenige Sonderzeichen: Zwei verschiedene Platzhalter und Zeichenbereiche werden unterstützt [von glob ].

Sie können also einige Dateien mit Mustern ausschließen.
Um beispielsweise Manifestdateien (Dateien, die mit beginnen _) mit glob auszuschließen , können Sie Folgendes verwenden:

files = glob.glob('files_path/[!_]*')
Kenly
quelle
9
Dies muss in der offiziellen Dokumentation sein, bitte jemand fügt dies zu docs.python.org/3.5/library/glob.html#glob.glob
Vitaly Zdanevich
6
Beachten Sie, dass Glob-Muster die vom OP festgelegte Anforderung nicht direkt erfüllen können: Nur Dateien ausschließen eph, die mit etwas anderem beginnen, aber mit etwas anderem beginnen können. [!e][!p][!h]filtert beispielsweise Dateien heraus, die mit beginnen eee.
Martijn Pieters
58

Sie können Sätze abziehen:

set(glob("*")) - set(glob("eph*"))
Neutrinus
quelle
3
Wirklich interessante Lösung! Aber mein Fall wird extrem langsam sein, um zweimal zu lesen. Auch wenn der Inhalt eines Ordners in einem Netzwerkverzeichnis groß ist, wird er wieder langsam. Aber auf jeden Fall sehr praktisch.
Anastasios Andronidis
Ihr Betriebssystem sollte Dateisystemanforderungen zwischenspeichern, also nicht so schlecht :)
Neutrinus
Ich habe es selbst versucht und habe gerade TypeError: nicht unterstützte Operandentypen für -: 'list' und 'list'
Tom Busby
1
@ TomBusby Versuchen Sie, sie in Mengen umzuwandeln: set(glob("*")) - set(glob("eph*")) (und beachten Sie * am Ende von "eph *")
Jaszczur
2
Nur als Randnotiz gibt glob Listen und keine Mengen zurück, aber diese Art von Operation funktioniert nur bei Mengen, weshalb Neutrinus sie umsetzt . Wenn Sie es brauchen, um eine Liste zu bleiben, wickeln Sie einfach die gesamte Operation in eine Besetzung:list(set(glob("*")) - set(glob("eph")))
Nathan Smith
48

Sie können Muster mit der globFunktion nicht ausschließen. Globs erlauben nur Einschlussmuster . Die Globbing-Syntax ist sehr begrenzt (selbst eine [!..]Zeichenklasse muss mit einem Zeichen übereinstimmen, daher handelt es sich um ein Einschlussmuster für jedes Zeichen, das nicht zur Klasse gehört).

Sie müssen Ihre eigene Filterung durchführen. Ein Listenverständnis funktioniert hier normalerweise gut:

files = [fn for fn in glob('somepath/*.txt') 
         if not os.path.basename(fn).startswith('eph')]
Martijn Pieters
quelle
2
Verwenden Sie iglobhier, um zu vermeiden, dass die vollständige Liste im Speicher gespeichert wird
Eugene Pankov
3
@Hardex: intern igloberzeugt sowieso Listen ; Alles, was Sie tun, ist, den Filter träge auszuwerten. Es wird nicht helfen, den Speicherbedarf zu verringern.
Martijn Pieters
@Hardex: Wenn Sie einen Globus im Verzeichnisnamen verwenden, dann haben Sie einen Punkt, dann wird höchstens ein os.listdir()Ergebnis beim Iterieren im Speicher gespeichert. Sie müssen somepath/*.txtjedoch alle Dateinamen in einem Verzeichnis im Speicher lesen und diese Liste dann auf nur die übereinstimmenden reduzieren.
Martijn Pieters
Sie haben Recht, es ist nicht so wichtig, aber auf Lager CPython , glob.glob(x) = list(glob.iglob(x)). Nicht viel Aufwand, aber immer noch gut zu wissen.
Eugene Pankov
Wird das nicht zweimal wiederholt? Einmal durch die Dateien, um die Liste zu erhalten, und das zweite Mal durch die Liste selbst? Wenn ja, ist es nicht möglich, dies in einer Iteration durchzuführen?
Ridhuvarshan
6

Spät zum Spiel, aber Sie können alternativ auch einfach eine Python filterauf das Ergebnis von glob:

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

oder Ersetzen des Lambda durch eine entsprechende Regex-Suche usw.

EDIT: Ich habe gerade festgestellt, dass wenn Sie vollständige Pfade verwenden startswith, dies nicht funktioniert, sodass Sie einen regulären Ausdruck benötigen

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
quelle
5

Wie wäre es, wenn Sie die bestimmte Datei überspringen, während Sie alle Dateien im Ordner durchlaufen? Der folgende Code überspringt alle Excel-Dateien, die mit 'eph' beginnen.

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

Auf diese Weise können Sie komplexere Regex-Muster verwenden, um einen bestimmten Satz von Dateien in einem Ordner einzuschließen / auszuschließen.

Azhar Ansari
quelle
5

Vergleichen Sie mit glob, ich empfehle pathlib, Filter ein Muster ist sehr einfach.

from pathlib import Path

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

und wenn Sie komplexere Muster filtern möchten, können Sie eine Funktion definieren, um dies zu tun, genau wie:

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

Mit diesem Code können Sie alle Dateien filtern, die mit ephoder beginnen epi.

Scott Ming
quelle
3

Um Dateien auszuschließen, die nicht mit einem regulären Shell-Ausdruck übereinstimmen, können Sie im Allgemeinen das folgende Modul verwenden 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)

Das Obige generiert zuerst eine Liste aus einem bestimmten Pfad und zeigt als nächstes die Dateien an, die den regulären Ausdruck nicht mit der gewünschten Einschränkung erfüllen.

Lord Henry Wotton
quelle
0

Wie in der akzeptierten Antwort erwähnt, können Sie Muster mit glob nicht ausschließen. Im Folgenden finden Sie eine Methode zum Filtern Ihres Glob-Ergebnisses.

Die akzeptierte Antwort ist wahrscheinlich die beste pythonische Methode, um Dinge zu tun. Wenn Sie jedoch der Meinung sind, dass Listenverständnisse etwas hässlich aussehen und Ihren Code ohnehin maximal numpythonisch machen möchten (wie ich), können Sie dies tun (beachten Sie jedoch, dass dies wahrscheinlich weniger effizient ist als die Listenverständnismethode):

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

(In meinem Fall hatte ich einige Bilderrahmen, Schrägrahmen und flache Rahmen in einem Verzeichnis und wollte nur die Bilderrahmen)

Ryan Farber
quelle
0

Wenn die Position des Zeichens nicht wichtig ist, z. B. um Manifestdateien (wo immer sie gefunden werden _) mit globund re- regulären Ausdrucksoperationen auszuschließen , können Sie Folgendes verwenden:

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

Oder eleganter mit - 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ć
quelle
-1

Sie können die folgende Methode verwenden:

# 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
quelle