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.