it-swarm-pt.tech

Convença o grep a exibir todas as linhas, não apenas aquelas com correspondências

Digamos que tenho o seguinte arquivo:

$ cat test

test line 1
test line 2
line without the search Word
another line without it
test line 3 with two test words
test line 4

Por padrão, grep retorna cada linha que contém o termo de pesquisa:

$ grep test test

test line 1
test line 2
test line 3 with two test words
test line 4

Passando o --color parâmetro para grep fará com que destaque a parte da linha que corresponde à expressão de pesquisa, mas ainda retorna apenas as linhas que contêm a expressão. Existe uma maneira de obter grep para produzir todas as linhas do arquivo de origem, mas realçar as correspondências?

Meu terrível truque atual para fazer isso (pelo menos em arquivos que não têm mais de 10000 linhas consecutivas sem correspondências) é:

$ grep -B 9999 -A 9999 test test

Screenshot of the two commands

Se grep não puder fazer isso, existe outra ferramenta de linha de comando que oferece a mesma funcionalidade? Eu brinquei com ack , mas também não parece ter uma opção.

127
Michael Mrozek
grep --color -E "test|$" yourfile

O que estamos fazendo aqui é comparar com o $ padrão e o padrão de teste, obviamente $ não tem nada para colorir, então apenas o padrão de teste fica colorido. O -E apenas ativa a correspondência estendida de regex.

Você pode criar uma função facilmente dessa forma:

highlight () { grep --color -E "$1|$" "${@:1}" ; }
194
jacksonh
ack --passthru --color string file

para Ubuntu e Debian, use ack-grep em vez de ack

ack-grep --passthru --color string file
40

Outra maneira de fazer isso corretamente e de forma portável com grep (além de usar duas expressões regulares com alternância como na resposta aceita) é via padrão nulo (e, respectivamente, cadeia nula).
Deve funcionar igualmente bem com os dois -E e -F alterna desde, por padrão :

-E
    Match using extended regular expressions. 
    [...] A null ERE shall match every line.

e

-F
    Match using fixed strings.
    [...] A null string shall match every line.

Portanto, é simplesmente uma questão de executar

grep -E -e '' -e 'pattern' infile

e respectivamente

grep -F -e '' -e 'string' infile
13
don_crissti

Eu tenho a seguinte função que eu uso para essas coisas:

highlight () {
    Perl -pe "s/$1/\e[1;31;43m$&\e[0m/g"
}

Internamente, parece meio feio, é agradável e fácil de usar, assim:

cat some_file.txt | highlight some_Word

ou, para um exemplo um pouco mais real:

tail -f console.log | highlight ERROR

Você pode alterar as cores para o que quiser (o que pode ser difícil com o grep - não tenho certeza) alterando o 1 e 31 e 43 (depois de \e[) para valores diferentes. Os códigos a serem usados ​​são todos sobre o local , mas aqui está uma introdução rápida: o 1 coloca o texto em negrito, o 31 torna vermelho, e o 43 dá um fundo amarelo. 32 ou 33 teriam cores diferentes e 44 ou 45 seriam origens diferentes: você entendeu a idéia. Você pode até fazê-lo piscar (com um 5) se você é tão inclinado.

Isso não usa nenhum módulo Perl especial, e o Perl é quase onipresente, então eu esperaria que funcionasse em qualquer lugar. A solução grep é muito inteligente, mas a opção --color no grep não está disponível em todos os lugares. Por exemplo, eu apenas tentei esta solução em uma caixa Solaris executando o bash e outro executando o ksh, e minha máquina local do Mac OS X executando o zsh. Tudo funcionou muito bem. Solaris engasgou com o grep --color solução, no entanto.

Além disso, o ack é incrível, e eu o recomendo para quem ainda não o descobriu, mas tive alguns problemas ao instalá-lo em alguns dos muitos servidores em que trabalho. (Eu esqueço o porquê: acho que relacionado aos módulos Perl necessários).

Desde que eu acho que nunca trabalhei em uma caixa Unix que não funcionou tem o Perl instalado (com exceção de sistemas do tipo embarcado, roteadores Linksys e outros) eu diria que essa é uma solução praticamente universal.

11
iconoclast

Em vez de usar o Grep, você pode usar Menos:

less file

Procure assim: /pattern Enter

Isso vai:

  1. role até a primeira linha correspondente
  2. produzir todas as linhas a partir daí
  3. destacar todas as correspondências

Para rolar para a próxima linha correspondente: n

Para rolar para a linha correspondente anterior: N

Para alternar o destaque: Esc u

Além disso, você pode alterar o realçando a cor se desejar.

3
Steven Penny

Podes tentar:

Perl -MTERM::ANSIColor -nle '/pattern/ ? print colored($_, 'color') : print' test

No entanto, não é muito portátil e, mesmo que o Perl esteja instalado, pode ser necessário fazer o download de outro módulo. Além disso, colorirá toda a linha, não apenas a palavra pesquisada.

2
gvkv

Nenhuma das respostas dadas até o momento fornece uma solução portátil .

Aqui está um portátil1 1 Função do shell I já postada em uma pergunta fechada como duplicada que não requer ferramentas não padrão ou extensões não padrão fornecidas com Perl, ack, ggrep, gsed, bash e os gostos, mas só precisam de um shell POSIX e dos utilitários obrigatórios POSIX sed e printf:

grepc()
{
  pattern=$1
  shift
  esc=$(printf "\033")
  sed 's"'"$pattern"'"'$esc'[32m&'$esc'[0m"g' "[email protected]"
}

Você pode usá-lo dessa maneira:

grepc string_to_search [file ...]

A cor de destaque pode ser ajustada usando um destes códigos no argumento do comando sed (32m sendo verde aqui):

30m black
31m red
33m yellow
34m blue
35m Magenta
36m cyan
37m white
7m reverse video

1 1 Desde que o seu terminal suporte sequências de escape de cores ANSI.

2
jlliagre

ripgrep

Use ripgrep com seus --passthru parâmetro:

rg --passthru pattern file.txt

É uma das ferramentas de grepping mais rápidas , pois é construída sobre mecanismo de regex do Rust , que usa autômatos finitos, SIMD e otimizações literais agressivas para tornar a pesquisa muito rápida.

--passthru - Imprime linhas correspondentes e não correspondentes.

Outra maneira de obter um efeito semelhante é modificando seu padrão para corresponder à sequência vazia. Por exemplo, se você estiver pesquisando usando rg foo então usando rg "^|foo" emitirá todas as linhas de todos os arquivos pesquisados, mas apenas as ocorrências de foo serão destacadas. Esse sinalizador permite o mesmo comportamento sem a necessidade de modificar o padrão.

2
kenorb

Existe uma maneira muito mais fácil de fazer isso para GNU grep, mas eu não acho que seja portátil (ou seja, BSD grep):

Em um tubo:

cat <file> | grep --color=always -z <query>

Em um arquivo:

grep --color=always -z <query> <file>

O crédito vai para resposta de Cyrus aqui .

1
Erik Nomitch

Uma versão sed funciona em bash e ash.

#highlight
hsed(){
    local pattern="$1"
    shift
    local r=`echo -e '\e'[31m`
    local c=`echo -e '\e'[0m`
    sed "s:${pattern//:/\:}:$r\0$c:g" "[email protected]"
}
0
yurenchen

O OP pediu grep, e é isso que RECOMENDO; mas depois de tentar resolver um problema com sed, para constar, aqui está uma solução simples:

sed $'s/main/\E[31m&\E[0m/g' testt.c

ou

cat testt.c | sed $'s/main/\E[31m&\E[0m/g'

Pintará main em vermelho.

  • \E[31m: sequência inicial de cor vermelha
  • \E[0m: marca de cor finalizada
  • &: o padrão correspondente
  • /g: todas as palavras em uma linha, não apenas a primeira
  • $'string' são sequências de caracteres bash com caracteres de escape interpretados

Em relação a grep, ele também funciona usando ^ (início da linha) em vez de $ (fim da linha). Exemplo:

egrep "^|main" testt.c

E apenas para mostrar esse pseudônimo louco que NÃO RECOMENDO, você pode até deixar as aspas abertas:

alias h='egrep -e"^|'
h main" testt.c
cat testt.c | h main"

todo o trabalho! :) Não se preocupe se você esquecer de fechar a cotação, o bash lembrará de você com um "caractere de linha contínua".

0
Dr Beco