glob esclude pattern


105

Ho una directory con un gruppo di file all'interno: eee2314, asd3442... e eph.

Voglio escludere tutti i file che iniziano ephcon la globfunzione.

Come posso farlo?

Risposte:


148

Le regole del modello per glob non sono espressioni regolari. Invece, seguono le regole standard di espansione del percorso Unix. Ci sono solo pochi caratteri speciali: sono supportati due diversi caratteri jolly e intervalli di caratteri [da glob ].

Quindi puoi escludere alcuni file con modelli.
Ad esempio, per escludere file manifesti (file che iniziano con _) con glob, puoi usare:

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

10
Questo deve essere nella documentazione ufficiale, per favore qualcuno lo aggiunga a docs.python.org/3.5/library/glob.html#glob.glob
Vitaly Zdanevich

6
Si noti che i pattern glob non possono soddisfare direttamente il requisito stabilito dall'OP: escludere solo i file che iniziano con ephma possono iniziare con qualsiasi altra cosa. [!e][!p][!h]filtrerà i file che iniziano con, eeead esempio.
Martijn Pieters

60

Puoi detrarre i set:

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

3
Soluzione davvero interessante! Ma il mio caso sarà estremamente lento per fare una lettura due volte. Inoltre, se il contenuto di una cartella è grande in una directory di rete, sarà di nuovo lento. Ma in ogni caso, davvero utile.
Anastasios Andronidis

Il tuo sistema operativo dovrebbe memorizzare nella cache le richieste del filesystem, quindi non così male :)
neutrinus

Ho provato io stesso, ho appena ricevuto TypeError: tipi di operandi non supportati per -: 'list' e 'list'
Tom Busby

1
@TomBusby Prova a convertirli in set: set(glob("*")) - set(glob("eph*")) (e nota * alla fine di "eph *")
Jaszczur

2
Come nota a margine, glob restituisce liste e non insiemi, ma questo tipo di operazione funziona solo sugli insiemi, ecco perché neutrinus l'ha lanciata. Se hai bisogno che rimanga un elenco, racchiudi semplicemente l'intera operazione in un cast:list(set(glob("*")) - set(glob("eph")))
Nathan Smith

48

Non puoi escludere modelli con la globfunzione, i glob consentono solo modelli di inclusione . La sintassi del globbing è molto limitata (anche una [!..]classe di caratteri deve corrispondere a un carattere, quindi è un modello di inclusione per ogni carattere che non è nella classe).

Dovrai fare il tuo filtro; una comprensione dell'elenco di solito funziona bene qui:

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

3
Utilizzare iglobqui per evitare di memorizzare l'elenco completo in memoria
Eugene Pankov

3
@Hardex: internamente, iglobproduce comunque liste ; tutto quello che fai è valutare pigramente il filtro. Non aiuterà a ridurre l'impronta di memoria.
Martijn Pieters

@ Hardex: se usi un glob nel nome della directory , avresti un punto, quindi al massimo un os.listdir()risultato viene mantenuto in memoria mentre iterate. Ma somepath/*.txtdeve leggere tutti i nomi di file in una directory in memoria, quindi ridurre quell'elenco solo a quelli che corrispondono.
Martijn Pieters

hai ragione, non è così importante, ma in azione CPython, glob.glob(x) = list(glob.iglob(x)). Non un granché ma comunque buono a sapersi.
Eugene Pankov

Non itera due volte? Una volta attraverso i file per ottenere l'elenco e il secondo attraverso l'elenco stesso? In tal caso, non è possibile farlo in un'unica iterazione?
Ridhuvarshan

6

In ritardo al gioco ma in alternativa potresti semplicemente applicare un pitone filteral risultato di glob:

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

o sostituendo il lambda con una ricerca regex appropriata, ecc ...

EDIT: Mi sono appena reso conto che se stai usando percorsi completi startswith, non funzionerà, quindi avresti bisogno di una regex

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

Che ne dici di saltare il file particolare durante l'iterazione su tutti i file nella cartella! Il codice seguente salterà tutti i file Excel che iniziano con "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)

In questo modo puoi utilizzare schemi regex più complessi per includere / escludere un particolare insieme di file in una cartella.


5

Confronta con glob, mi raccomando pathlib, filtrare un pattern è molto semplice.

from pathlib import Path

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

e se vuoi filtrare pattern più complessi, puoi definire una funzione per farlo, proprio come:

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

usa quel codice, puoi filtrare tutti i file che iniziano con epho iniziano con epi.


4

Più in generale, per escludere file che non rispettano alcune espressioni regolari di shell, potresti usare 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)

Quanto sopra genererà prima un elenco da un determinato percorso e successivamente verranno visualizzati i file che non soddisfano l'espressione regolare con il vincolo desiderato.


0

Come menzionato dalla risposta accettata, non è possibile escludere pattern con glob, quindi il seguente è un metodo per filtrare il risultato glob.

La risposta accettata è probabilmente il miglior modo pitonico per fare le cose, ma se pensi che la comprensione delle liste sembri un po 'brutta e vuoi comunque rendere il tuo codice massimamente numpitonico (come ho fatto io) allora puoi farlo (ma nota che questo è probabilmente meno efficiente rispetto al metodo di comprensione delle liste):

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

(Nel mio caso, avevo alcuni frame di immagine, frame bias e frame piatti tutti in una directory e volevo solo i frame dell'immagine)


0

Se la posizione del carattere non è importante, ad esempio per escludere file manifest (ovunque si trovi _) con globe re- operazioni di espressioni regolari , puoi usare:

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

O con in un modo più elegante - list comprehension

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

for mach in filtered:
    print(mach)

-1

Puoi usare il metodo seguente:

# 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.  
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.