grep ignora os arquivos que começam com ponto [duplicado]

2

Deixe-me dar um exemplo:

$ echo Hello > file1
$ echo Hello > file2
$ echo Hello > .file3
$ grep Hello * 2>/dev/null
file1:Hello
file2:Hello

Aqui você pode ver o grep ignorado .file3 , que está começando em .

Resultado esperado:

$ grep Hello * 2>/dev/null
.file3:Hello
file1:Hello
file2:Hello

No caso de ls , há um argumento -a para informar que não ignore as entradas que começam com . , mas não consigo encontrar nenhum recurso para grep

Então, existe alguma maneira de dizer que grep não ignora as entradas que começam com . ? ou por que grep os ignora?

    
por Pandya 20.02.2016 / 10:10

7 respostas

12

* não corresponde ao período inicial . na expansão de nome de arquivo. A regra foi especificada por POSIX .

Com correspondência de padrões, funciona:

$ sh -c 'case . in *) echo 1;; esac'
1

POSIXly:

find . ! -name . -prune -type f -exec grep 'pattern' /dev/null {} +

Essa abordagem tem vantagem sobre o uso de globalização de casca. Você nunca receberá o erro Argument list too long quando houver muitos arquivos.

    
por 20.02.2016 / 12:50
9

Como outros afirmaram, o * glob não incluirá arquivos ocultos (aqueles cujo nome começa com um ponto) por padrão. Uma maneira simples de usar isso é usar dois globs:

grep Hello * .*

No lado negativo, exceto com zsh , fish ou shells baseados no shell Forsyth (hoje em dia, pdksh e derivativos como mksh , posh ou OpenBSD sh ) que causarão grep para reclamar sobre a pesquisa pelos diretórios . e .. :

$ grep Hello * .*
file1:Hello
file2:Hello
grep: .: Is a directory
grep: ..: Is a directory
.file3:Hello

Você pode simplesmente ignorar esses erros (eles não são importantes neste contexto) ou você pode usar um loop simples e verificar se o alvo é um arquivo regular (após a resolução do symlink):

$ for file in .* *; do [ -f "$file" ] && grep -H -- Hello "$file"; done 
.file3:Hello
file1:Hello
file2:Hello
    
por 20.02.2016 / 13:31
8

Para globs incluir arquivos ocultos, exceto . e .. :

  • zsh :

    grep Hello ./*(D)
    

    (você também precisa de ./ para nomes de arquivos que começam com - ). Ou:

    (set -o dotglob; grep Hello ./*)
    

    Outra vantagem de zsh globs é que você pode especificar que deseja apenas arquivos regulares (com o qualificador . glob):

    grep Hello ./*(D.)
    
  • ksh93 :

    (FIGNORE='.?(.)'; grep Hello ./*)
    
  • bash :

    (shopt -s dotglob; grep Hello ./*)
    
  • tcsh :

    (set globdot; grep Hello ./*)
    
  • fish :

    grep Hello {.,}*
    
  • Concha e derivados de Forsyth ( pdksh , OpenBSD sh , posh , mksh ...) e fish :

    grep Hello ./.* ./*
    
  • rc , es :

    grep Hello ./.[~.]* ./..?* ./*
    
  • Bourne shell, ksh88 e derivados de conchas Almquist:

    grep Hello ./.[!.]* ./..?* ./*
    
  • csh :

    grep Hello ./.[^.]* ./..?* ./*
    

Com zsh , (t)csh e fish , isso não executará o comando se a (s) glob (s) não corresponderem a nenhum arquivo. Em outros shells, os globs que não são correspondidos serão passados como estão para grep , e grep irá reclamar que o arquivo correspondente não existe.

    
por 20.02.2016 / 16:09
7

grep não ignora nada. * , por padrão, não corresponde a arquivos com um . inicial. Se você tem o GNU grep, é mais fácil usar sua opção recursiva, em vez de confiar nos curingas do shell:

grep Hello . -r
    
por 20.02.2016 / 10:24
6

Outros disseram corretamente que * não corresponderá aos arquivos que começam com ponto. Várias soluções foram dadas em muitas respostas, a maioria das quais tem algum loop-hole ou outro (como incluir. & ...; ou excluir arquivos que começam com múltiplos Pontos; ou incluir Sub-Diretórios; ou envolver um comando muito longo -line) todos os quais fornecem alguns novos pontos para esta questão.

Minha solução simples (para usuários do bash) é para usar shopt -s dotglob , que informa o bash para incluir os Arquivos Dot em * glob .
Para compatibilidade com POSIX ou uso de outros shells, espero que as outras respostas sejam úteis.
Destaques de shopt -s dotglob Solution : Não incluirá. e ..; Não incluirá sub-diretórios de maneira recursiva; É muito curto; Pode ser colocado no arquivo .bashrc.

    
por 20.02.2016 / 10:44
3

A expansão de * é feita pelo shell executando o comando.
Por padrão, shells omitem arquivos dot (arquivos ocultos).

A solução mais simples e mais portátil (não zsh) seria usar:

$ grep Hello * .[!.]* 

O segundo glob .[!.]* é equivalente a .[^.]* e é necessário para alguns shells (use o formulário ^ para zsh, csh e tcsh ou .[~.]* para rc / es ). br> Faz com que os arquivos de pontos apareçam na lista para o grep.

Se houver necessidade de processar nomes de arquivos diferentes de .. iniciando com 2 pontos, adicione um terceiro glob Página de referência do FAQ do UNIX :

$ grep Hello * .[!.]* ..?*

Se você quiser ver o que está acontecendo, faça:

echo grep Hello * .[!.]* ..?*

E teste por que isso não funciona: echo grep Hello * .*

ksh | bash

Em ksh ou bash com extglob ativo (ativado por padrão no uso interativo para o bash):

grep Hello .!(.|) *

Ou apenas para bash, basta usar o dotglob:

shopt -s dotglob; grep Hello *

zsh

grep Hello *(D.)
    
por 20.02.2016 / 11:37
2

Tente isso

$ grep Hello 'ls -A' 2>/dev/null
.file3:Hello
file1:Hello
file2:Hello

EDITAR:

O código acima não produzirá resultados com espaço no nome do arquivo, como sugerido por techraf. Para resolver esse problema, tente seguir o código:

$ echo Hello > .file 4
$ find . -print0 | xargs -0 grep Hello 2>/dev/null
    .file3:Hello
    .file 4:Hello
    file1:Hello
    file2:Hello

Aqui find . pesquisará nos subdiretórios também. Para limitar a pesquisa pelo diretório atual, use o parâmetro -maxdepth=1

Da página man do find

-print0

      True; print the full file name on the standard  output,  followed
      by  a  null  character  (instead  of  the  newline character that
      ‘-print’ uses).  This allows file names that contain newlines  or
      other  types  of  white space to be correctly interpreted by pro-
      grams that process the find output.  This option  corresponds  to
      the ‘-0’ option of xargs.

E da página man do xargs

-0

Input items are terminated by a null character instead of by whitespace, and the quotes and backslash are not special (every charac‐ ter is taken literally). Disables the end of file string, which is treated like any other argument. Useful when input items might contain white space, quote marks, or backslashes. The GNU find -print0 option produces input suitable for this mode.

    
por 20.02.2016 / 10:21