Encontre vários padrões de palavras em arquivos

0

Tenho cerca de 50000 arquivos (.txt) e mais itens na pasta filesdir. Os valores: 'fax', 'phone', 'address' são apresentados em diferentes configurações nesses arquivos. Preciso encontrar todos os arquivos que contêm "fax" E "telefone" e não contêm "endereço". Eu tentei loop com alguns comandos do grep. ls dá "muitos argumentos". Então eu tentei:

find /filesdir/ -maxdepth 1 -name '*.txt' -exec grep -l 'fax' \; grep -l 'phone' \; grep -l -v 'address'

Por que isso não funciona?

    
por Josef Klimuk 27.03.2018 / 16:33

4 respostas

1

Existem várias razões que não funcionariam:

  • você omitiu o espaço reservado {} para o -exec
  • você está tentando comandos -exec multiple grep com uma única invocação
  • Suspeito que sua lógica tenha falhas, pois a operação padrão para localizar é lógico AND , enquanto você presumivelmente deseja fax OU phone AND not address

Eu não testei totalmente, mas acho que você quer algo mais como

find /filesdir/ -maxdepth 1 -name '*.txt' -exec grep -q 'fax\|phone' {} \; -exec grep -lv 'address' {} \;
    
por steeldriver 27.03.2018 / 16:51
2

git grep

Você pode usar git grep para vários padrões combinados usando expressões booleanas, por exemplo:

git grep --all-match --no-index -e "fax" --and -e "phone" --and --not -e "address"

Você pode combinar diferentes padrões com expressões Booleanas como --and , --or e --not .

--all-match When giving multiple pattern expressions, this flag is specified to limit the match to files that have lines to match all of them.

--no-index Search files in the current directory that is not managed by Git.

-l/--files-with-matches/--name-only Show only the names of files.

-e The next parameter is the pattern. Default is to use basic regexp.

Outros parâmetros a considerar:

--threads Number of grep worker threads to use.

-q/--quiet/--silent Do not output matched lines; exit with status 0 when there is a match.

Para alterar o tipo de padrão, você também pode usar -G / --basic-regexp (padrão), -F / --fixed-strings , -E / --extended-regexp , -P / --perl-regexp , -f file e outros.

Verifique man git-grep para ajuda adicional.

grep

Aqui está a sintaxe grep , que usa a cadeia de substituições de comandos :

grep -L "address" $(grep -l "phone" $(grep -rl "fax" .))

Explicação:

  1. Localize os nomes dos arquivos com o padrão "fax" ( grep -rl "fax" . ).
  2. Filtre os nomes dos arquivos que estão com o padrão "phone" ( grep -l "phone" $(cmd) ).
  3. Filtre mais abaixo para excluir arquivos que não tenham address ( grep -L "address" $(cmd) ).

Se você estiver trabalhando com dados grandes, considere usar ripgrep .

find

O exemplo acima pode não funcionar bem com arquivos com espaços em branco, portanto, aqui está a versão com find :

find . -type f -name '*.txt' \
  -execdir bash -c 'grep -L "address" "$(grep -l "phone" "$(grep -l "fax" "{}")")"' ';' \
2>/dev/null

Veja também: Verifique se existem várias strings ou expressões regulares em um arquivo

    
por kenorb 11.04.2018 / 12:35
1

Imprimir os nomes dos arquivos e seu conteúdo em uma linha para cada arquivo

Acho que esta linha de comando fará isso:

find -maxdepth 1 -name "*.txt" -exec echo "{} :" \; -exec cat {} \; -exec echo EOF \;| tr '\n' ' '|sed 's/EOF /\n/g'|grep -iv 'address'|grep -i 'fax'|grep -i 'phone'

Explicação:

  • para cada arquivo (encontrado por find )

    • ecoa o nome do arquivo
    • imprima o conteúdo
    • imprima um sinalizador de fim de arquivo (que deve ser diferente do que pode estar dentro dos arquivos. Selecione este sinalizador cuidadosamente! Eu uso EOF, você pode precisar de algo mais.
  • para toda a saída

    • converta as novas linhas em espaços para obter tudo em uma linha
    • converta os sinalizadores de fim de arquivo em novas linhas

    Agora, o conteúdo de cada arquivo está em uma linha separada, adequada para grep .

  • e finalmente

    • pula linhas com 'endereço'
    • da saída restante, selecione linhas com 'fax'
    • da saída restante, selecione linhas com 'telefone'

Imprimindo apenas os nomes dos arquivos

A linha de comando anterior imprime os nomes dos arquivos e o conteúdo do arquivo (mesclado em uma linha), o que é bom para testes, mas não para o processamento de milhares de arquivos.

A seguinte linha de comando imprime apenas os nomes dos arquivos. Ele usa ':::' para separar cada nome de arquivo do conteúdo do arquivo.

find -maxdepth 1 -name "*.txt" -exec echo "{} :::" \; -exec cat {} \; -exec echo EOF \;| tr '\n' ' '|sed 's/EOF /\n/g'|grep -iv 'address'|grep -i 'fax'|grep -i 'phone' | sed 's/ :::.*//'
    
por sudodus 27.03.2018 / 17:33
1

Para encontrar arquivos (compatíveis com arquivos incluindo espaço em branco / ou nova linha), estes não contêm o padrão address :

find -type f ! -exec grep -q 'address' {} \; -print 

e imprima somente aqueles que contêm os padrões fax e phone em qualquer ordem no arquivo inteiro:

find -type f ! -exec grep -q 'address' {} \; \
               -exec grep -qP '(?s)(?=.*?fax)(?=.*?phone)' {} \; -print

Ou POSIXly:

find -type f ! -exec grep -q 'address' {} \; \
               -exec grep -q 'fax' {} \; \
               -exec grep -q 'phone' {} \; -print

Ou assumindo que não há \n ewline no nome dos arquivos, então:

grep -lP '(?s)(?=.*?fax)(?=.*?phone)' * |xargs -d'\n' grep -L address
  • (?=pattern) : Lookahead positivo: a construção lookahead positiva é um par de parênteses, com o parêntese de abertura seguido por um ponto de interrogação e um sinal de igual.

  • (?s) Conhecido "dot-all", que diz ao grep para permitir que o ponto . corresponda também a \n caracteres do ewline.

  • O .*? significa corresponder a todos os caracteres . que ocorreram zero ou mais vezes * , enquanto eles são opcionais seguidos por um padrão ( fax ou phone ). O ? torna tudo opcional antes dele (significa zero ou uma vez em que tudo corresponde a .* )

leitura futura:

Grupos Regex lookahead, lookbehind e atomic

    
por devWeek 08.05.2018 / 12:45