Como usar grep em todos os arquivos de forma não recursiva em um diretório?

35

Eu quero procurar uma seqüência de texto em todos os arquivos em um diretório (e não em seus subdiretórios; sei que a -ropção faz isso, mas não é isso que eu quero).

  1. Corrida

    grep "string" /path/to/dir
    

    é suposto ser capaz de fazer isso, eu li, mas isso me dá o erro:

    grep: dir: é um diretório

  2. Em seguida, tentei executar grepem vários arquivos.

    grep "string" .bashrc .bash_aliases funciona perfeitamente.

    grep "string" .bash* funciona como pretendido também.

    grep "string" * me dá os erros:

    grep: data: Is a directory
    grep: Desktop: Is a directory
    grep: Documents: Is a directory
    grep: Downloads: Is a directory
    ...
    

Apenas os erros são impressos, não recebo as linhas correspondentes. Eu tentei usar a -sopção, mas sem sucesso.

Então, minhas perguntas:

  1. Por que não consigo usar grepem um diretório, como em (1), quando devo fazê-lo? Eu já vi isso em vários exemplos na Internet.
    Edit : Quando digo "usando grep em um diretório", quero dizer "pesquise em todos os arquivos desse diretório, exceto seus subdiretórios". Eu acredito que é isso que o grep faz quando você passa um diretório para ele no lugar de um arquivo. Estou incorreto?

  2. Por favor, me dê uma explicação sobre o funcionamento grepque explicaria o comportamento dos comandos em (2).
    Editar : Deixe-me ser mais específico. Por que o uso de curingas para especificar vários arquivos para procurar trabalho com .bash*e não com *ou mesmo ./*?

  3. Como posso pesquisar todos os arquivos em um diretório (e não seus subdiretórios) usando grep?

John Red
fonte
Além disso, você está confiando no shell que expande curingas, como *, conhecido como globbing. Globbing não inclui nomes de arquivos que começam com um ponto .bashrccomo o padrão. Você pode definir opções de shell para incluir esses arquivos, mas poderá ficar um pouco confuso se não souber o que está fazendo. Um bom guia para a compreensão globing pode ser encontrada aqui mywiki.wooledge.org/glob
Arronical
Não sei por que, mas sempre procurei arquivos ocultos, e sempre funcionou. Não mudei nenhuma configuração ou algo assim. Como apontei em (2), ele também funciona grep "string" .bash*.
John
Desculpe, meu último exemplo estava incorreto. Você também pode procurar em arquivos ocultos e suprimir o "é um diretório" porque o Linux tecnicamente vê os diretórios como um tipo diferente de arquivo. O comando seria então: grep "string" * .* 2>/dev/nullougrep -s "string" * .*
Terrance 25/05
Também este stackoverflow.com/q/9217185/3701431
Sergiy Kolodyazhnyy

Respostas:

41

No Bash, um glob não se expandirá para arquivos ocultos; portanto, se você deseja pesquisar todos os arquivos em um diretório, especifique os arquivos ocultos .*e os não ocultos *.

Para evitar os erros "É um diretório", você pode usar -d skip, mas no meu sistema também recebo um erro grep: .gvfs: Permission denied , então sugiro usar -s, que oculta todas as mensagens de erro.

Portanto, o comando que você está procurando é:

grep -s "string" * .*

Se você estiver pesquisando arquivos em outro diretório:

grep -s "string" /path/to/dir/{*,.*}

Outra opção é usar a dotglobopção shell, que fará com que um globo inclua arquivos ocultos.

shopt -s dotglob
grep -s "string" *

Para arquivos em outro diretório:

grep -s "string" /path/to/dir/*

† Alguém mencionou que eu não deveria receber esse erro. Eles podem estar certos - eu li algumas coisas, mas não consegui entender nada disso.

wjandrea
fonte
Existe alguma razão para o espaço entre *e .*?
Hashim
2
@Hashim Compare a saída echo * .*e echo *.*execute em seu diretório pessoal, e a diferença deve ser óbvia. Caso contrário, LMK e eu vou explicar.
Wjandrea 23/09/19
Interessante, echo *mostra arquivos e pastas echo *.*não ocultos, echo .*mostra arquivos não ocultos, mostra todos os arquivos e echo * .*mostra todos os arquivos e diretórios. Mas por que a razão do espaço entre os dois no último caso? Parece uma bagunça para mim. Não existe uma maneira de combinar os dois para obter os mesmos resultados? Ou então, existe uma explicação de sintaxe do porquê os dois precisam ser separados aqui, ou é * .*um caso excepcional?
Hashim
1
@Hashim Não sei bem como você chegou a essas conclusões, então deixe-me explicar. Primeiro, diretórios são arquivos nesse contexto. Em globs, *representa todos os arquivos não ocultos (ou seja, nomes de arquivos que não começam com um ponto); .*representa todos os arquivos escondidos (ou seja, nomes de arquivos que não começam com um ponto); e *.*representa todos os arquivos não ocultos que contêm um ponto. Em echo * .*, os dois globos devem estar separados porque são globos diferentes: um para não oculto, um para oculto. Embora, como escrevi na minha resposta, você possa *incluir arquivos ocultos ativando a dotglobopção shell.
Wjandrea # 23/18
1
O uso *.*é comum no Windows (DOS) como uma maneira de listar todos os arquivos, mas o * nix inclui apenas arquivos com um ponto, portanto, não faz sentido no * nix. Em vez disso, você usa *para listar todos os arquivos, exceto arquivos ocultos, e .*para listar arquivos ocultos.
thomasrutter 6/03
11

Você precisa da -d skipopção adicionada.

  1. O Grep está pesquisando dentro dos arquivos. Você pode pesquisar recursivamente, como você disse, se quiser pesquisar arquivos dentro de um diretório.

  2. Por padrão, o grep lê todos os arquivos e detecta os diretórios. Como, por padrão, você não definiu o que fazer com os diretórios com a -dopção, ele fornece erro de saída.

  3. Pesquisando apenas dentro do diretório pai seria `grep -d skip" string "./*

anonymous2
fonte
Para mais informações sobre grep, consulte man grep.
anonymous2
(a) Por favor, veja a edição. (b) O uso -d skipnão funciona; é basicamente o mesmo que -s; veja também a edição. (c) Não, grep -d skip "string" ./*também não funciona.
John
7

Os veteranos provavelmente fariam isso:

find . -type f -print0 | xargs -0 grep "string"
Dathompson
fonte
3
Por que não find . -type f -exec grep string {} +?
Wchargin
5
Você também quer -maxdepth 1.
Wchargin
@chargin: se você quiser o nome do arquivo na saída quando houver apenas um arquivo que eu acho que você querfind . -type f -maxdepth 1 -exec grep string /dev/null {} +
Gregory Nisbet
1
@ GregoryNisbet: Basta passar -Hpara grep.
wchargin 14/03
2

Reformular - você deseja grep os arquivos em um nível de subdiretório, mas não recursa em todos os subdiretórios?

grep forthis  *  */*

Ou se você não quiser os arquivos no diretório atual

grep forthis  */*

Observe que isso não encontrará diretórios começando com um ponto.

grep forthis  .*/*    */*   

deve fazer esse trabalho.

Há também -maxdepthe -mindepthrestrição parâmetros disponíveis para o findcomando também.

Criggie
fonte
Não grep forthis */*procuraria arquivos no diretório atual e em um diretório inativo?
Hashim
@Hashim não, principalmente - porque */*apenas combina as coisas com uma barra. Se você tivesse um arquivo nomeado a/bno diretório atual, `* / * corresponderia a isso.
Criggie
0

Aqui está um exemplo para ignorar diretórios sem ignorar todos os erros:

grep --directories='skip' 'searchString' *
Mojtaba Rezaeian
fonte