padrão de exclusão global


98

Eu tenho um diretório com um monte de arquivos dentro: eee2314, asd3442... e eph.

Desejo excluir todos os arquivos que começam ephcom a globfunção.

Como eu posso fazer isso?

Respostas:


138

As regras de padrão para glob não são expressões regulares. Em vez disso, eles seguem as regras padrão de expansão de caminho do Unix. Existem apenas alguns caracteres especiais: dois curingas diferentes e intervalos de caracteres são suportados [de glob ].

Portanto, você pode excluir alguns arquivos com padrões.
Por exemplo, para excluir arquivos de manifestos (arquivos começando com _) com glob, você pode usar:

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

10
Deve estar na documentação oficial, por favor, alguém adicione a docs.python.org/3.5/library/glob.html#glob.glob
— Vitaly Zdanevich

6
Observe que os padrões glob não podem cumprir diretamente o requisito definido pelo OP: excluir apenas os arquivos que começam com, ephmas podem começar com qualquer outra coisa. [!e][!p][!h]irá filtrar os arquivos que começam com, eeepor exemplo.
— Martijn Pieters

58

Você pode deduzir conjuntos:

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

3
Solução realmente interessante! Mas meu caso vai ser extremamente lento para fazer uma leitura duas vezes. Além disso, se o conteúdo de uma pasta for grande em um diretório de rede, ficará lento novamente. Mas, em qualquer caso, muito útil.
— Anastasios Andronidis

Seu sistema operacional deve armazenar em cache as solicitações do sistema de arquivos, então não é tão ruim :)
— neutrinus

Tentei sozinho, acabei de obter TypeError: tipo (s) de operando não suportado (s) para -: 'lista' e 'lista'
— Tom Busby

1
@TomBusby Tente convertê-los em conjuntos: set(glob("*")) - set(glob("eph*")) (e observe * no final de "eph *")
— Jaszczur

2
Apenas como uma observação lateral, glob retorna listas e não conjuntos, mas esse tipo de operação só funciona em conjuntos, por isso os neutrinos o lançam. Se você precisar que ele permaneça uma lista, simplesmente envolva a operação inteira em um elenco:list(set(glob("*")) - set(glob("eph")))
— Nathan Smith

48

Você não pode excluir padrões com a globfunção, globs permitem apenas padrões de inclusão . A sintaxe de globbing é muito limitada (até mesmo uma [!..]classe de caractere deve corresponder a um caractere, portanto, é um padrão de inclusão para cada caractere que não está na classe).

Você terá que fazer sua própria filtragem; uma compreensão de lista geralmente funciona bem aqui:

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

2
Use iglobaqui para evitar o armazenamento da lista completa na memória
— Eugene Pankov

3
@Hardex: internamente, iglobproduz listas de qualquer maneira ; tudo o que você faz é avaliar o filtro preguiçosamente. Isso não ajudará a reduzir o consumo de memória.
— Martijn Pieters

@Hardex: se você usar um glob no nome do diretório , terá um ponto, então, no máximo, um os.listdir()resultado é mantido na memória conforme você itera. Mas somepath/*.txttem que ler todos os nomes de arquivo em um diretório na memória e, em seguida, reduzir essa lista para apenas aqueles que correspondem.
— Martijn Pieters

você está certo, não é tão importante, mas em estoque CPython glob.glob(x) = list(glob.iglob(x)),. Não é muito uma sobrecarga, mas é bom saber.
— Eugene Pankov

Isso não itera duas vezes? Uma vez através dos arquivos para obter a lista e a segunda através da própria lista? Em caso afirmativo, não é possível fazer isso em uma iteração?
— Ridhuvarshan

6

Atrasado no jogo, mas você pode, alternativamente, apenas aplicar um python filterao resultado de glob:

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

ou substituindo o lambda por uma pesquisa regex apropriada, etc ...

EDIT: Acabei de perceber que se você estiver usando caminhos completos, o startswithnão funcionará, então você precisa de um 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

Que tal pular um arquivo específico enquanto itera todos os arquivos na pasta! O código abaixo pularia todos os arquivos do Excel que começam com '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)

Dessa forma, você pode usar padrões regex mais complexos para incluir / excluir um determinado conjunto de arquivos em uma pasta.


5

Compare com glob, eu recomendo pathlib, filtrar um padrão é muito simples.

from pathlib import Path

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

e se você quiser filtrar um padrão mais complexo, pode definir uma função para fazer isso, assim:

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

usar esse código, você pode filtrar todos os arquivos que começam com ephou começam com epi.


3

De forma mais geral, para excluir arquivos que não estão em conformidade com alguma regexp de shell, você pode usar o 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)

O código acima irá primeiro gerar uma lista de um determinado caminho e, em seguida, exibir os arquivos que não satisfarão a expressão regular com a restrição desejada.


0

Conforme mencionado pela resposta aceita, você não pode excluir padrões com glob, então o seguinte é um método para filtrar seu resultado glob.

A resposta aceita é provavelmente a melhor maneira pythônica de fazer as coisas, mas se você acha que as compreensões de lista parecem um pouco feias e quer tornar seu código numpythônico máximo de qualquer maneira (como eu fiz), então você pode fazer isso (mas note que isso é provavelmente menos eficiente do que o método de compreensão de lista):

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

(No meu caso, eu tinha alguns quadros de imagem, quadros enviesados ​​e quadros planos, todos em um diretório e queria apenas os quadros de imagem)


0

Se a posição do caractere não for importante, por exemplo, para excluir arquivos de manifestos (onde quer que seja encontrado _) com globe re- operações de expressão regular , você pode usar:

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

Ou de uma forma mais elegante - list comprehension

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

for mach in filtered:
    print(mach)

-1

Você pode usar o método abaixo:

# 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.  
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.