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}' {} +
Meu problema é que preciso:
regex_pattern
em todos os arquivos (pesquisa profunda) em um determinado diretório raiz 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.
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
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/'