Comando shell para localizar arquivos contendo uma palavra, mas não a segunda palavra

4

Tudo

Eu tenho os dois arquivos abaixo na minha máquina linux e queria descobrir o arquivo que contém "word1" e não contém "word99"

file1.txt
  word1
  word2
  word3
  word4
  word5

file2.txt
  word1
  word2
  word3
  word99

Eu tenho usado o comando abaixo para arquivos incluindo "word1", mas não consegui encontrar nenhuma informação sobre como modificá-lo para obter nomes de arquivos contendo "word1" mas não "word99"

find . -name '*.*' -exec grep -r 'word1' {} \; -print > output.txt

Todos os ponteiros seriam úteis.

Obrigado Sandy

    
por Sandeep K Gujje 07.08.2016 / 19:26

3 respostas

4

    $ grep -lr 'word1' * | xargs grep -L 'word99'
    file1.txt

onde:

    -l, --files-with-matches
         Only the names of files containing selected lines are written
         to standard output.
    -R, -r, --recursive
         Recursively search subdirectories listed.
    -L, --files-without-match
         Only the names of files not containing selected lines are written
         to standard output.

Na primeira parte do comando antes do pipe, obtemos:

    $ grep -lr 'word1' * 
    file1.txt
    file2.txt

O comando acima analisa recursivamente os arquivos dentro dos subdiretórios e lista os arquivos que contêm a palavra word1 , ou seja, file1.txt e file2.txt .

Posteriormente, na segunda parte, | xargs grep -L 'word99' , o canal envia file1.txt e file2.txt como entrada para xargs , o que os fornece para grep como argumentos. grep , em seguida, lista o arquivo que não contém word99 usando a opção -L , ou seja, file1.txt .

Precisamos de xargs aqui, pois na primeira parte do comando, obtemos file1.txt e file2.txt como a saída na stdout. Precisamos analisar o conteúdo desses arquivos e não as strings file1.txt e file2.txt .

O comando a seguir também fornece o mesmo resultado (invertendo a maneira como procuramos / excluímos as strings):

      $ grep -Lr 'word99' * | xargs grep -l 'word1'
      file1.txt
    
por 12.08.2016 / 14:53
0

Isso encontra arquivos que contêm word1 :

$ find . -name '*.*' -type f -exec grep -q 'word1' {} \; -print
./file1.txt
./file2.txt

Isso encontra arquivos que contêm word1 , mas não word99 :

$ find . -name '*.*' -type f -exec grep -q 'word1' {} \; '!' -exec grep -q 'word99' {} \; -print 
./file1.txt

Para salvar a saída em um arquivo:

find . -name '*.*' -type f -exec grep -q 'word1' {} \; '!' -exec grep -q 'word99' {} \; -print >output.txt

O teste -exec grep -q word99 {} \; retorna True para arquivos com word99 . Colocamos ! na frente dele para negar o valor de retorno. Assim, ! -exec grep -q word99 {} \; retorna True para arquivos que não não têm word99 . O ! está entre aspas simples porque, se a expansão do histórico estiver ativada, ! pode ser um caractere ativo em shell.

Notas:

  1. A opção -q foi adicionada a grep para torná-la silenciosa. Com -q , o grep definirá o código de saída correto, mas não exibirá linhas correspondentes no stdout.

  2. O teste -type f foi adicionado a find para que só retorne nomes de arquivos regulares.

por 07.08.2016 / 20:30
0

O título da pergunta diz "arquivos contendo" uma palavra. No entanto, na sua pergunta, você menciona "obter os nomes de arquivo contendo" uma palavra. Essas são coisas diferentes. Felizmente, ambos são bem simples, então vou mostrar a vocês dois.

Para encontrar arquivos que contenham uma palavra:

grep -iR "word1" .

O -i diz para ignorar o caso. O -R é recursivo (ou seja, os subdiretórios são pesquisados). (A letra maiúscula é documentada pelo OpenBSD e mais similar a ls, então eu prefiro o over -r.) O período especifica onde começar a procurar.

Para encontrar nomes de arquivos contendo uma palavra:

find . -iname "word1"

O -iname é uma versão de "nome" insensível a maiúsculas e minúsculas.

O período especifica onde começar a procurar. O diretório atual costuma ser uma boa escolha.

Observação: você fez referência a ". " em um dos seus exemplos. Isso foi ótimo para o DOS, e normalmente bom no Microsoft Windows, mas é um péssimo hábito para o ambiente Unix. Vendo isso me faz pensar que você está familiarizado com o Windows. Bem, entenda que no Windows, "FIND" (ou "find") localiza o texto nos arquivos. Unix é diferente: "grep" localiza texto em arquivos, e "find" localiza nomes de arquivos.

Agora, para excluir a palavra 99 e colocar isso em um arquivo de texto, adicione o seguinte texto:

| grep -v word99 >> output.txt

Esta é a chave do pipe, quase sempre Shift-Backslash.

Então, por exemplo, se você quiser fazer as duas coisas, use:

grep -iR "word1" . | grep -v word99 >> output.txt
find . -iname "word1" | grep -v word99 >> output.txt

A parte antes do caractere pipe executará um comando e enviará a saída para um pipe no estilo Unix. Em seguida, o conteúdo é enviado do pipe para a entrada padrão do próximo comando. grep -v examinará a entrada padrão que recebe e excluirá o que você deseja. grep -v enviará os resultados restantes para sua saída padrão. O > > irá redirecionar a saída padrão do comando anterior para o final do arquivo de texto especificado.

O motivo pelo qual você não vê opções documentadas no comando "find", sobre como excluir texto, é que o Unix foi muito elaborado com essa idéia de criar programas mais simples e usar a técnica de piping para causar efeitos elaborados. . Nos ambientes da Microsoft, o código antigo da Microsoft era particularmente mais complicado com o manuseio de tubos, de modo que os programas basicamente tentavam incorporar mais funcionalidades em cada programa. Por um lado, isso parece mais simples para o usuário final (tendo tudo embutido), mas essa abordagem não tem consistência. Quando você estiver usando o Unix, não tenha medo da tubulação: uma vez que você se acostumar com isso, você pode achar que isso simplifica muito as coisas, mas porque você pode usar suas ferramentas simples em muitas situações, e então você não precisa para re-aprender técnicas simples repetidamente (para cada programa diferente).

    
por 12.08.2016 / 15:57