localiza arquivos não correspondentes lista de padrões de nome de arquivo

6

Eu me vejo precisando encontrar e identificar arquivos estranhos (de cerca de 900K arquivos em uma unidade de 2T). Há muitos arquivos que desejo manter, e tenho padrões de nome de arquivo para esses arquivos bons conhecidos. O que eu quero é localizar os arquivos que não se encaixam em nenhum dos padrões.

Como faço para encontrar arquivos que não correspondam a uma lista de padrões de nome de arquivo?

Eu posso executar find para obter uma lista de todos os arquivos, e eu poderia usar grep -v no resultado, usando uma lista de padrões armazenados em um arquivo. Este é o método canônico, ou você tem uma maneira concisa de encontrar esses arquivos que não estão em conformidade?

Esclarecimento - baseado nas respostas, aqui está um pouco mais de informação. Espero ter vários padrões (> 20, talvez > 100), quero armazená-los em um arquivo e, certamente, quero uma maneira fácil de adicionar novos padrões. Eu preferiria evitar editar diretamente uma grande lista de parâmetros de busca (frágeis), mas construir essa lista pode funcionar.

    
por ChuckCottrill 17.10.2013 / 06:29

2 respostas

3

Desde que você mencionou Perl ...

#!/usr/bin/perl

use strict;
use warnings;
use File::Find qw{find};

my %patterns;
while (<>) {
  chomp;
  $patterns{$_}++;
}

die "No pattern supplied\n" unless keys %patterns;

find( 
    sub{
           my $matches_a_pattern=0;
           for my $pattern (keys %patterns){
               my $glob_pattern = $pattern;
               for($glob_pattern){
                   s/\./\./g;
                   s/\*/.*/g;
                   s/\?/./g;
               }
               $matches_a_pattern++ if ( /\Q$pattern\E/ or /$glob_pattern/);
           }

           print "$File::Find::name\n" unless $matches_a_pattern;
     }
    , '.' )

Invoque isso como

/path/to/my/script file_with_patterns

Substitua o . no final pelo topo da árvore que você deseja percorrer.

    
por 17.10.2013 / 11:38
18

find(1) é poderoso o suficiente para fazer o que você precisa. Basta coletar todos os nomes em conformidade em uma expressão usando parênteses e, em seguida, negá-lo para mostrar nomes de arquivos não conformes . Por exemplo, para mostrar todos os arquivos não denominados *.txt , *.bz2 ou *.zip :

$ find . \! \( -name \*.txt -o -name \*.bz2 -o -name \*.zip \)

Você pode usar -not em vez de \! com GNU e BSD find . Não é compatível com POSIX, mas não requer uma fuga para impedir que o shell o interprete.

Para construir a expressão a partir de padrões em um arquivo, é uma pequena questão de script de shell:

#!/bin/sh
set --
while IFS= read -r pattern
do
    set -- "$@" -o "$pattern"
done < .fnpatterns
if [ $# -ne 0 ]; then
  shift
  set -- -not \( "$@" \)
fi
find . "$@"

Isso espera um arquivo no diretório atual chamado .fnpatterns com um padrão por linha. Para imitar o one-liner acima, ele precisaria conter:

*.txt
*.bz2
*.zip

Observe que o script de shell escapa dos caracteres * nos padrões para você.

Você pode tornar isso arbitrariamente complexo. Algumas ideias:

  • Adicione -type f ao comando find para mostrar apenas arquivos normais, não diretórios.

  • Transmita o nome do arquivo padrão como um argumento em vez de esperá-lo em um local fixo

  • Mantenha o arquivo padrão onde está, mas adicione -o -name .fnpatterns ao comando find acumulado para que ele não apareça na saída. (Isso também evitaria a necessidade de o shift hack "comer" o lead -o na expressão construída.)

  • Adicione ações ao comando find via -exec ou similar.

  • Permitir linhas em branco ou comentários no arquivo de padrões

por 17.10.2013 / 06:33

Tags