patrón de exclusión glob

105

Tengo un directorio con un montón de archivos dentro: eee2314, asd3442... y eph.

Quiero excluir todos los archivos que comienzan ephcon la globfunción.

¿Cómo puedo hacerlo?

Anastasios Andronidis
fuente

Respuestas:

148

Las reglas de patrón para glob no son expresiones regulares. En cambio, siguen las reglas de expansión de ruta estándar de Unix. Hay sólo unos pocos caracteres especiales: se admiten dos comodines diferentes y rangos de caracteres [de glob ].

De modo que puede excluir algunos archivos con patrones.
Por ejemplo, para excluir archivos de manifiesto (archivos que comienzan con _) con glob, puede usar:

files = glob.glob('files_path/[!_]*')
Kenly
fuente
10
Esto debe estar en la documentación oficial, por favor, que alguien agregue esto a docs.python.org/3.5/library/glob.html#glob.glob
Vitaly Zdanevich
6
Tenga en cuenta que los patrones globales no pueden cumplir directamente con el requisito establecido por el OP: excluir solo los archivos que comienzan con ephpero pueden comenzar con cualquier otra cosa. [!e][!p][!h]filtrará los archivos que comiencen con, eeepor ejemplo.
Martijn Pieters
60

Puede deducir conjuntos:

set(glob("*")) - set(glob("eph*"))
neutrino
fuente
3
¡Solución realmente interesante! Pero mi caso va a ser extremadamente lento para hacer una lectura dos veces. Además, si el contenido de una carpeta es grande en un directorio de red, volverá a ser lento. Pero en cualquier caso, muy útil.
Anastasios Andronidis
Su sistema operativo debería almacenar en caché las solicitudes del sistema de archivos, por lo que no es tan malo :)
neutrinus
Probé esto yo mismo, acabo de obtener TypeError: tipo (s) de operando no admitido para -: 'lista' y 'lista'
Tom Busby
1
@TomBusby Intente convertirlos en conjuntos: set(glob("*")) - set(glob("eph*")) (y observe * al final de "eph *")
Jaszczur
2
Como nota al margen, glob devuelve listas y no conjuntos, pero este tipo de operación solo funciona en conjuntos, de ahí la razón por la que neutrinus la lanza. Si necesita que siga siendo una lista, simplemente envuelva toda la operación en un molde:list(set(glob("*")) - set(glob("eph")))
Nathan Smith
48

No puede excluir patrones con la globfunción, los globs solo permiten patrones de inclusión . La sintaxis globbing es muy limitada (incluso una [!..]clase de carácter debe coincidir con un carácter, por lo que es un patrón de inclusión para cada carácter que no está en la clase).

Tendrá que hacer su propio filtrado; una lista de comprensión suele funcionar bien aquí:

files = [fn for fn in glob('somepath/*.txt') 
         if not os.path.basename(fn).startswith('eph')]
Martijn Pieters
fuente
3
Use iglobaquí para evitar almacenar la lista completa en la memoria
Eugene Pankov
3
@Hardex: internamente, iglobproduce listas de todos modos ; todo lo que hace es evaluar perezosamente el filtro. No ayudará a reducir la huella de memoria.
Martijn Pieters
@Hardex: si usa un glob en el nombre del directorio, entonces tendría un punto, entonces, como máximo, un os.listdir()resultado se mantiene en la memoria mientras itera. Pero somepath/*.txttiene que leer todos los nombres de archivo en un directorio en la memoria, luego reducir esa lista a solo aquellos que coincidan.
Martijn Pieters
tienes razón, no es tan importante, pero en la acción CPython, glob.glob(x) = list(glob.iglob(x)). No es una gran sobrecarga, pero es bueno saberlo.
Eugene Pankov
¿No se repite dos veces ?. ¿Una vez a través de los archivos para obtener la lista y la segunda a través de la lista misma? Si es así, ¿no es posible hacerlo en una iteración?
Ridhuvarshan
6

Tarde en el juego, pero también puedes aplicar una pitón filteral resultado de glob:

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

o reemplazando el lambda con una búsqueda de expresiones regulares apropiada, etc.

EDITAR: Me acabo de dar cuenta de que si está utilizando rutas completas startswith, no funcionará, por lo que necesitaría una expresión regular

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

¿Qué tal si se salta el archivo en particular mientras se itera sobre todos los archivos de la carpeta? El siguiente código omitiría todos los archivos de Excel que comienzan 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)

De esta manera, puede usar patrones de expresiones regulares más complejos para incluir / excluir un conjunto particular de archivos en una carpeta.

Azhar Ansari
fuente
5

Comparar con glob, recomiendo pathlib, filtrar un patrón es muy simple.

from pathlib import Path

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

y si desea filtrar un patrón más complejo, puede definir una función para hacer eso, como:

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

use ese código, puede filtrar todos los archivos que comienzan con epho comienzan con epi.

Scott Ming
fuente
4

De manera más general, para excluir archivos que no cumplen con algunas expresiones regulares de shell, puede usar el módulo 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)

Lo anterior generará primero una lista a partir de una ruta determinada y luego mostrará los archivos que no satisfagan la expresión regular con la restricción deseada.

Lord Henry Wotton
fuente
0

Como se menciona en la respuesta aceptada, no puede excluir patrones con glob, por lo que el siguiente es un método para filtrar su resultado glob.

La respuesta aceptada es probablemente la mejor forma pitónica de hacer las cosas, pero si crees que las listas de comprensión se ven un poco feas y quieres que tu código sea lo más numpythonic de todos modos (como hice yo), entonces puedes hacer esto (pero ten en cuenta que probablemente sea menos eficiente que el método de comprensión de listas):

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

(En mi caso, tenía algunos marcos de imagen, marcos de sesgo y marcos planos en un directorio y solo quería los marcos de imagen)

Ryan Farber
fuente
0

Si la posición del carácter no es importante, es decir, por ejemplo, para excluir archivos de manifiesto (donde sea que se encuentre _) con globy re- operaciones de expresión regular , puede usar:

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

O de una manera más elegante - 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ć
fuente
-1

Puede utilizar el siguiente método:

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