Aqui está uma solução Perl. Isso deve ser muito mais rápido para milhares de arquivos:
perl -e '@bad=grep{/(\d+)\.end/ && % 12 != 0}@ARGV; unlink @bad' *
Que pode ser ainda mais condensado em:
perl -e 'unlink grep{/(\d+)\.end/ && % 12 != 0}@ARGV;' *
Se você tiver muitos arquivos e não puder usar o simples *
, poderá fazer algo como:
perl -e 'opendir($d,"."); unlink grep{/(\d+)\.end/ && % 12 != 0} readdir($dir)'
Quanto à velocidade, aqui está uma comparação dessa abordagem e da shell fornecida em uma das outras respostas:
$ touch file.{01..64}.name.{00001..01000}.end
$ ls | wc
64000 64000 1472000
$ time for f in ./* ; do file="${f%.*}"; if [[ $((10#${file##*.} % 12)) -ne 0 ]]; then rm "$f"; fi; done
real 2m44.258s
user 0m9.183s
sys 1m7.647s
$ touch file.{01..64}.name.{00001..01000}.end
$ time perl -e 'unlink grep{/(\d+)\.end/ && % 12 != 0}@ARGV;' *
real 0m0.610s
user 0m0.317s
sys 0m0.290s
Como você pode ver, a diferença é enorme, conforme o esperado .
Explicação
- O
-e
está simplesmente informandoperl
para executar o script fornecido na linha de comando. -
@ARGV
é uma variável especial que contém todos os argumentos dados ao script. Como estamos dando*
, ele conterá todos os arquivos (e diretórios) no diretório atual. -
O
grep
pesquisará a lista de nomes de arquivos e procurará qualquer que corresponda a uma sequência de números, um ponto eend
(/(\d+)\.end/)
. -
Como os números (
\d
) estão em um grupo de captura (parênteses), eles são salvos como. Portanto, o
grep
verificará se esse número é um múltiplo de 12 e, se não for, o nome do arquivo será retornado. Em outras palavras, a matriz@bad
contém a lista de arquivos a serem excluídos. -
A lista é então passada para
unlink()
, o que remove os arquivos (mas não os diretórios).