Grep em muitos diretórios, mas procure somente no subdiretório específico de cada diretório, não em todos os subdiretórios

0

Meu caso:

dir1 
  subdir1
      FooFile
  subdir2

dir2 
  subdir1
      FooFile
  subdir2

Então, se eu cd dir1 , eu posso facilmente fazer algo como find . | xargs grep "Foo" para listar os nomes de todos os arquivos contendo Foo .

O problema é que existem muitos subdiretórios e arquivos, que essa pesquisa leva muito tempo. Gostaria de entrar recursivamente em cada diretório principal e, em seguida, ir especificamente para o subdiretório ONE (subdir1) e, em seguida, fazer o grep.

Qual é a melhor maneira de listar os nomes de todos os arquivos que contêm Foo de todos os diretórios? Para cada diretório com nomes diferentes, subdir1 é sempre um nível abaixo de dir1 e é sempre denominado subdir1 exatamente.

    
por Cath 16.03.2016 / 00:02

3 respostas

1

Se você quiser procurar em e em todos os diretórios (sub) chamados subdir1 que são um nível abaixo do nível superior, você pode fazer

find */subdir1 …

Se você está procurando arquivos cujos nomes contenham Foo , você pode fazer

find */subdir1 -type f -name "*Foo*" -print

Ou você poderia fazer

find */subdir1 -type f -print | grep "Foo"

mas isso incluiria todos os arquivos em um diretório cujo nome inclui a string Foo , por exemplo, dir42/subdir1/Foods_I_Like/pizza e dir42/subdir1/Foods_I_Like/chicken .

Se você procura arquivos que contêm Foo (isto é, cujo conteúdo contém Foo ), você pode fazer

find */subdir1 -type f -print | xargs grep "Foo"

Notas:

  • Isso funciona porque a sinopse (uso) de find é semelhante
    find [options] [starting-point...] [expression]
    isto é, você pode invocar find uma vez em vários pontos de partida; como em:
    find   dir1/subdir1 dir2/subdir1   [expression]
  • Isso lida com arquivos e diretórios cujos nomes incluem espaço (s) muito bem.
  • Se você estiver procurando por arquivos ou diretórios cujos nomes contenham Foo , deixe de fora o -type f dos comandos correspondentes.
  • É claro que você deve citar "*Foo*" e não deve citar */subdir1 . A citação de "Foo" é opcional - não dói, mas você não precisa citar palavras que não contêm caracteres especiais.
  • Você pode deixar de fora o -print , pois é a ação padrão.
por 16.03.2016 / 05:25
1

e

grep "foo" */subdir1/*  */subdir1/.*

(com base na sua pergunta atual, isso parece se encaixar no projeto. A menos que haja muitos subdiretórios "subdir1" que o shell não possa fornecer a lista inteira para o grep.

Você pode adicionar -q e testar se ele sair com 0 se você quiser apenas ver se um "foo" aparece no arquivo

Você também pode fazer um grep recursivo e, em seguida, descartar o que não precisa (pesado em I / O, mas simples):

grep -r "foo" . | grep "^\./[^/][^/]*/subdir1/[^/][^/]*:"

(Veja os comentários abaixo: aqui, mesmo se o nome contiver ":", isso funcionará como você encontrou um nome de arquivo sob subdir1, e esse arquivo contém foo. Ele pode perder um arquivo que contém uma nova linha em seu nome, entretanto, como no segundo grep, ele não verá o primeiro nome "./firstleveldir/", então o segundo grep irá descartá-lo ...)

    
por 16.03.2016 / 06:21
0

Você pode fazer isso com um script, por exemplo,

#!/bin/sh
find . -type d | while IFS= read -r pathname
do
    for name in "$pathname"/subdir1/*Foo*
    do
        [ -f "$name" ] && echo "$name"
    done
done

com as advertências habituais sobre novas linhas em nomes de caminho. Testado com esta árvore:

./dir2
./dir2/subdir1
./dir2/subdir1/FooFile
./dir2/subdir2
./subdir1
./subdir1/FooFile
./dir spacew
./dir spacew/subdir1
./dir spacew/subdir1/FooFile
./dir spacew/subdir2
./dir1
./dir1/subdir1
./dir1/subdir1/FooFile

o script produzido

./subdir1/FooFile
./dir2/subdir1/FooFile
./dir spacew/subdir1/FooFile
./dir1/subdir1/FooFile

A pergunta era ambígua em relação ao uso de grep (como foi escrito, não houve diferença em relação a echo , exceto pela possibilidade de usar expressões regulares em vez de curingas de shell). Como alternativa, você pode usar grep diretamente:

#!/bin/sh
find . -type f -name '*Foo*' | grep -E 'subdir1/Foo[^/]*$' | while IFS= read -r pathname
do
    echo "$pathname"
done

Leitura adicional:

por 16.03.2016 / 01:01