Como pesquisar em arquivos específicos que correspondam a um padrão

5

Como posso encontrar uma palavra em arquivos específicos que correspondam a um padrão. por exemplo. procurando por version em CMake* arquivos encontrados recursivamente no diretório atual.

    
por Meysam 16.12.2013 / 07:33

5 respostas

8

Se você quiser ver o nome do arquivo e o número da linha, POSIXly:

find . -name 'CMake*' -type f -exec grep -nF /dev/null version {} +

(você não quer usar ; aqui, o que executaria um grep por arquivo). Esse é o equivalente padrão do GNUism:

find . -name 'CMake*' -type f -print0 | xargs -r0 grep -nHF {} +

find (no primeiro), xargs (no segundo) irá passar tantos argumentos para grep quanto possível sem exceder o limite no número de argumentos que você pode passar para um comando. Ao fazer essa divisão, pode acontecer que, para a última execução, apenas um argumento seja passado para grep , caso em que grep não imprimiria o nome do arquivo. É por isso que você precisa do /dev/null (ou -H com o GNU grep ).

Com -type f , estamos considerando apenas arquivos regulares (não dispositivos, links simbólicos, canais, diretórios ...).

Se você quiser usar o GNUisms, você pode usar o GNU grep capacidade de descer uma árvore de diretórios:

 grep -rHnF --include='CMake*' version .

Você não quer usar -R , pois isso faz com que grep siga os links simbólicos ao descer a árvore de diretórios e ler os dispositivos, fifos, sockets ...

Essa versão é mais segura e eficiente, mas não é portável.

    
por 16.12.2013 / 11:02
3

Use find para selecionar os arquivos, em seguida, o grep para pesquisar nos arquivos:

find . -name "CMake*" -print0 | xargs -0 grep -F version

usando xargs , você não tem grep iniciado para cada arquivo encontrado.

    
por 16.12.2013 / 07:39
3

Só para mostrar que você pode fazer isso sem precisar da ajuda de find . Você pode usar a capacidade de grep para reciclar o sistema de arquivos também. Supondo que sua versão de grep tenha a opção -R :

$ grep -R version | awk -F: '/CMake.*:/ {print $1}'

Exemplo

Eu criei alguns dados de amostra que incluíam arquivos chamados CMake1-3 que continham a string version , assim como um arquivo chamado CMake0 que não continha. Eu também criei 2 arquivos chamados afile que também continham a string version .

$ tree .
.
|-- CMake1
|-- dir1
|   |-- dirA1
|   |   '-- CMake1
|   |-- dirA2
|   '-- dirA3
|-- dir2
|   |-- dirA1
|   |   '-- CMake0
|   |-- dirA2
|   |   |-- afile
|   |   '-- CMake2
|   '-- dirA3
'-- dir3
    |-- dirA1
    |-- dirA2
    |   '-- afile
    '-- dirA3
        '-- CMake3

Agora, quando eu executo o comando acima:

$ grep -R version | awk -F: '/CMake.*:/ {print $1}'
CMake1
dir2/dirA2/CMake2
dir3/dirA3/CMake3
dir1/dirA1/CMake1

Detalhes

Os comandos acima produzem uma lista como esta em grep :

$ grep -R version 
CMake1:version
dir2/dirA2/CMake2:version
dir2/dirA2/afile:version
dir3/dirA2/afile:version
dir3/dirA3/CMake3:version
dir1/dirA1/CMake1:version

E awk é usado para localizar todas as cadeias que contêm CMake.*: e para dividir essas cadeias em dois pontos ( : ) e para retornar apenas o primeiro campo dessa divisão, ou seja, o caminho da variável nome de um arquivo CMake* correspondente.

2 grep's + PCRE

Versões mais modernas do grep geralmente incluem o que é chamado de PCRE - Perl Compatible Exprssions Compatible . Assim, você poderia usar 2 grep de comandos, com o segundo usando PCRE para extrair apenas a parte do caminho do arquivo, omitindo o :version da string do primeiro grep .

Exemplo

$ grep -R version | grep -Po '.*CMake.*(?=:version)'
CMake1
dir2/dirA2/CMake2
dir3/dirA3/CMake3
dir1/dirA1/CMake1

O -o retornará apenas a parte correspondente, enquanto -P é o que habilita o PCRE. Dentro da expressão regular, estamos usando um lookahead, ( ?=... ), no final, para selecionar apenas strings que têm um :version à direita. Essa visão é apenas para ajudar a alinhar nosso padrão, ele não é incluído nos resultados que retornamos nem é parte do padrão real que estamos buscando, ou seja, CMake.* .

Números de linha

Você também pode incluir a opção -n no primeiro grep , para que o número da linha em que a string version foi encontrada também possa ser incluído na saída.

Exemplo

$ grep -Rn version | grep -Po '.*CMake.*(?=:version)'
CMake1:1
dir2/dirA2/CMake2:9
dir3/dirA3/CMake3:1
dir1/dirA1/CMake1:1

Para que o primeiro exemplo funcione, você precisa alterar os comandos awk :

$ grep -Rn version | awk -F: '/CMake.*:/ {print $1":"$2}'  
CMake1:1
dir2/dirA2/CMake2:9
dir3/dirA3/CMake3:1
dir1/dirA1/CMake1:1

O primeiro exemplo dá a você a oportunidade de mover o número da linha, já que já analisamos em um campo separado via awk .

Exemplo

Aqui podemos colocar o número primeiro.

$ grep -Rn version | awk -F: '/CMake.*:/ {print $2":"$1}'  
1:CMake1
9:dir2/dirA2/CMake2
1:dir3/dirA3/CMake3
1:dir1/dirA1/CMake1
    
por 16.12.2013 / 08:48
1

Use uma combinação de encontrar um grep:

find . -name "Cmake*" -exec grep version {} \;

O exemplo pesquisa recursivamente a partir do diretório atual e executa grep nos arquivos correspondentes.

    
por 16.12.2013 / 07:37
1
find . -name "CMake*" -exec grep -H version {} \;
    
por 16.12.2013 / 07:39