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?

Anastasios Andronidis
fonte

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/[!_]*')
Kenly
fonte
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*"))
neutrino
fonte
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')]
Martijn Pieters
fonte
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']
K Raphael
fonte
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.

Azhar Ansari
fonte
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.

Scott Ming
fonte
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.

Lord Henry Wotton
fonte
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)

Ryan Farber
fonte
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)
Milovan Tomašević
fonte
-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.  
KK2491
fonte