Ajuda a pesquisar em arquivos padrões de regex, recursivamente, com saída especializada

3

Meu problema é que preciso:

  1. Localize todas as linhas correspondentes a regex_pattern em todos os arquivos (pesquisa profunda) em um determinado diretório raiz
  2. Para cada linha correspondente, a saída:
    • Nome do arquivo
    • Número da linha que contém a correspondência
    • Conteúdo da linha
    • O padrão de expressão regular
  3. Importe os dados acima para o Excel (assim, um CSV ou um formato de saída delimitado vem à mente)

Qual é a maneira mais fácil de realizar essa tarefa?

Para provar eu pensei um pouco sobre isso, eu escreveria um script Perl que pegasse como entrada um único nome de arquivo totalmente qualificado e um padrão regex, e processasse as linhas usando o Perl aproximado abaixo (ainda não tentei , mas é assim que minha primeira tentativa se assemelharia):

while (<FILE>) {
  $line_number++;

  if ($_ =~ m/regex_pattern/) {
    # output: file_name\tline_number\tregex_pattern\t$_
    # ignore escaping issues for the time being
  }
}

Ainda não tenho certeza de como passaria o conteúdo de cada diretório com uma pesquisa recursiva nesse script Perl. Eu posso fazer a pesquisa em Perl, mas tenho certeza que há uma maneira Unix / Linux bacana de fazer isso.

Eu não sou casado com Perl. Se há uma maneira de fazer isso unindo as ferramentas padrão do Unix / Linux, isso seria incrível. Se não, eu prefiro usar o Perl, já que estou familiarizado com a sua sintaxe.

    
por jglouie 04.06.2013 / 03:43

3 respostas

4

Algo parecido com isto?

find /search/root -type f -exec awk 'BEGIN{pattern="regex_pattern"} $0 ~ pattern {printf "%s,%s,%s,%s\n",FILENAME,FNR,$0,pattern}'  {} +
    
por 04.06.2013 / 04:15
2
start cmd:> find . -type f -name 'search*' -exec awk -v regex=foo \
cont. cmd:>   '$0 ~ regex {print FILENAME,FNR,regex,$0 }' {} +
./searchfile1 1 foo a_foo_b
./searchfile2 1 foo foo
    
por 04.06.2013 / 04:17
1

Em Perl, aproveitando o manipulador de arquivo nulo que opera nos argumentos da linha de comando:

#!/usr/bin/perl -n
$, = "\t";  # separator added between arguments to print
while (<>) {
  if (/regex_pattern/) {
    # $ARGV contains the current file name, $. contains the current line number,
    # $_ contains the current line including its terminating newline
    print $ARGV, $., 'regex_pattern', $_;
  }
  $. = 0 if eof;  # reset the line number between files
}

Para passar os nomes dos arquivos para o script Perl, em ksh93 ou bash ≥4 ou zsh, você pode usar o ** padrão para percorrer subdiretórios recursivamente. Em ksh, você precisa ativar esse padrão primeiro com set -o globstar . No bash, você precisa ativá-lo com shopt -s globstar .

shopt -s globstar
name_of_perl_script **/*

Se o seu shell não tiver ** , ou se você encontrar um erro de "linha de comando longo demais", poderá usar find .

find . -type f -exec name_of_perl_script {} +

Você também pode fazer isso combinando ferramentas mais especializadas. Você provavelmente já conhece o grep para pesquisar um padrão em arquivos. A opção -n faz com que imprima o número de cada linha correspondente. Passar /dev/null como um nome de arquivo é um truque para garantir que grep também imprima o nome do arquivo (ele não será feito se houver um único arquivo em sua linha de comando).

grep -n 'regex_pattern' **/*

Tudo o que falta é alterar os separadores, se necessário ( grep insere : entre o nome do arquivo, o número da linha e o conteúdo da linha) e insere o regex no local correto. Este trabalho de substituição simples é um ajuste perfeito para sed . Certifique-se de citar o regex corretamente.

find . -type f -exec grep -n 'regex_pattern' {} + |
sed 's/^\([^:]*\)\([^:]*\)/\t\tregex_pattern\t/'
    
por 05.06.2013 / 02:48