O que é um comando do Linux para encontrar arquivos contendo algumas strings, mas não outras?

4

Estou tentando pesquisar vários arquivos XML para determinadas cadeias de caracteres, mas não para outras cadeias, e estou tendo problemas para criar um comando para fazer isso. Eu só quero listar os nomes dos arquivos que correspondem aos critérios de inclusão / exclusão. Eu tenho tentado:

find . -name *.xml -exec grep -li "string1\|string2" {} \; | xargs grep -Li "string3\|string4"

Mas estou tendo problemas porque os nomes de arquivos retornados de localizar têm espaços em suas os nomes e o segundo grep divide todos em pequenos pedaços e, claro, não encontra tais arquivos. Eu tentei adicionar -0 aos xargs e ele remove os erros, mas diz "Nome do arquivo longo demais "e só executa o primeiro grep.

Como faço para ajustar esse comando para que ele funcione corretamente em arquivos com espaços nos nomes?

    
por Cicerone Cojocaru 13.06.2011 / 15:33

4 respostas

3

Há mais de uma maneira de fazer isso. Isso deve manter o número total de processos executados no mínimo:

find . -name \*.xml -print0          \   # List of *.xml files (NUL-terminated)
  | xargs -0 grep -Zli 'string[12]'  \   # is input to first grep, which sends (NUL-term'd)
  | xargs -0 grep -Li  'string[34]'      # file list to second grep

Obrigado Matt Gibson por nos lembrar do -Z flag para o GNU grep.

    
por 13.06.2011 / 15:55
3

Você pode fazer tudo em um find , o que evita todos os problemas com espaços em nomes de arquivos. Algo como

find . -exec grep -liq "string1\|string2" {} \; -not -exec grep -liq "string3\|string4" {} \; -print

O "-q" suprime toda a saída do grep. O -exec primary retorna true quando o processo sai com o status 0, como o grep faz quando encontra uma correspondência, e o -not primary inverte isso. Portanto, colocamos diretamente duas condições no find e, como resultado, imprimimos apenas os nomes de arquivos que satisfazem ambos - nenhum tubo é necessário!

    
por 13.06.2011 / 15:43
2

Como mencionado no meu comentário, acho que tudo o que está faltando é o sinalizador -Z no primeiro grep para acompanhar o -0 que você estava experimentando em xargs :

find . -name "*.xml" -exec grep -liZ "string1\|string2" {} \; | xargs -0 grep -Li "string3\|string4"
    
por 13.06.2011 / 15:55
0

Se o fator limitante for CPU (ou seja, seu disco é rápido) e você tiver mais núcleos de CPU, você pode usar o GNU Parallel:

find . -type f| parallel grep -Lq foo {} '||' grep -l bar {}

Ao executar os dois grep s imediatamente após o outro, é provável que os arquivos ainda estejam no cache de disco. Se o disco procura são lentos, você pode adicionar -j1 para desabilitar o paralelismo.

Assista ao vídeo de introdução para saber mais: link

    
por 14.06.2011 / 16:39