it-swarm.it

Convincere grep a produrre tutte le righe, non solo quelle con le corrispondenze

Di 'che ho il seguente file:

$ 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

Per impostazione predefinita, grep restituisce ogni riga che contiene il termine di ricerca:

$ grep test test

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

Passando il parametro --color A grep, si evidenzierà la parte della riga che corrisponde all'espressione di ricerca, ma restituisce comunque solo le righe che contengono l'espressione. C'è un modo per ottenere grep per produrre ogni riga nel file sorgente, ma evidenziare le corrispondenze?

Il mio attuale attacco terribile per raggiungere questo obiettivo (almeno sui file che non hanno più di 10000 righe consecutive senza corrispondenze) è:

$ grep -B 9999 -A 9999 test test

Screenshot of the two commands

Se grep non riesce a farlo, esiste un altro strumento da riga di comando che offre le stesse funzionalità? Ho armeggiato con ack , ma non sembra avere nemmeno un'opzione per questo.

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

Quello che stiamo facendo qui è la corrispondenza con il $ modello e modello di prova, ovviamente $ non ha nulla da colorare, quindi solo il modello di prova ottiene colore. Il -E attiva solo la corrispondenza regex estesa.

È possibile creare una funzione da esso facilmente in questo modo:

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

per Ubuntu e Debian, usare ack-grep invece di ack

ack-grep --passthru --color string file

Un altro modo per farlo correttamente e in modo portabile con grep (oltre a usare due regex con alternanza come nella risposta accettata) avviene tramite il modello null (e rispettivamente la stringa null).
Dovrebbe funzionare ugualmente bene con entrambi -E e -F passa da, secondo lo standard :

-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.

Quindi è semplicemente una questione di corsa

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

e rispettivamente

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

Ho la seguente funzione che uso per tali cose:

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

Internamente sembra un po 'brutto, è bello e facile da usare, in questo modo:

cat some_file.txt | highlight some_Word

o, per un esempio leggermente più reale:

tail -f console.log | highlight ERROR

Puoi cambiare i colori in qualsiasi cosa ti piaccia (che potrebbe essere difficile con grep - non sono sicuro) cambiando 1 e 31 e 43 (dopo \e[) a valori diversi. I codici da usare sono tutti sopra il luogo , ma ecco una breve introduzione: il 1 mette in grassetto il testo, il 31 lo rende rosso e il 43 dà uno sfondo giallo. 32 o 33 avrebbe colori diversi e 44 o 45 sarebbero sfondi diversi: hai avuto l'idea. Puoi persino farlo lampeggiare (con un 5) se sei così propenso.

Questo non utilizza alcun modulo Perl speciale e Perl è quasi onnipresente, quindi mi aspetto che funzioni quasi ovunque. La soluzione grep è molto intelligente, ma l'interruttore --color su grep non è disponibile ovunque. Ad esempio, ho appena provato questa soluzione su un box Solaris con bash e un altro con ksh e il mio computer Mac OS X locale con zsh. Tutto ha funzionato bene. Solaris è soffocato sul grep --color soluzione, tuttavia.

Inoltre, ack è fantastico e lo consiglio a tutti coloro che non lo hanno ancora scoperto, ma ho avuto dei problemi con l'installazione su alcuni dei molti server su cui lavoro. (Dimentico il perché: penso sia correlato ai moduli Perl richiesti).

Dal momento che non credo di aver mai mai lavorato su una scatola Unix che non ha funzionato hanno installato Perl (ad eccezione di sistemi di tipo embedded, router Linksys e simili), direi che questa è praticamente una soluzione universalmente utilizzabile.

11
iconoclast

Invece di usare Grep, puoi usare Less:

less file

Cerca in questo modo: /pattern Enter

Questo sarà:

  1. scorrere fino alla prima riga corrispondente
  2. emette ogni linea a partire da lì in poi
  3. evidenzia tutte le partite

Per scorrere fino alla riga corrispondente successiva: n

Per scorrere fino alla riga corrispondente precedente: N

Per attivare l'evidenziazione: Esc u

Inoltre puoi cambiare evidenziando il colore se vuoi.

3
Steven Penny

Puoi provare:

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

Tuttavia, non molto portatile, e anche se Perl è installato, potrebbe essere necessario scaricare un altro modulo. Inoltre, colora l'intera riga, non solo la parola di ricerca.

2
gvkv

Nessuna delle risposte fornite finora fornisce una soluzione portatile .

Ecco un portatile1 Funzione shell I già pubblicata in una domanda chiusa come duplicata che non richiede strumenti non standard o estensioni non standard fornite con Perl, ack, ggrep, gsed, bash e simili, ma necessita solo di una shell POSIX e delle utilità obbligatorie POSIX sed e printf:

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

Puoi usarlo in questo modo:

grepc string_to_search [file ...]

Il colore di evidenziazione può essere regolato usando uno di questi codici nell'argomento del comando sed (qui 32m è verde):

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

1 Finché il tuo terminale supporta sequenze di escape colori ANSI.

2
jlliagre

ripgrep

Usa ripgrep con il suo --passthru parametro:

rg --passthru pattern file.txt

È uno degli strumenti per il grepping più veloce , dato che è costruito sopra il motore regex di Rust che utilizza automi finiti, SIMD e ottimizzazioni letterali aggressive per rendere la ricerca molto veloce.

--passthru - Stampa entrambe le linee corrispondenti e non corrispondenti.

Un altro modo per ottenere un effetto simile è modificando il modello in modo che corrisponda alla stringa vuota. Ad esempio, se stai cercando utilizzando rg foo quindi usando rg "^|foo" invece emetterà ogni riga in ogni file cercato, ma verranno evidenziate solo le occorrenze di pippo. Questo flag abilita lo stesso comportamento senza dover modificare il modello.

2
kenorb

C'è un modo molto più semplice per farlo per GNU grep ma non penso che sia portatile (cioè BSD grep):

In una pipa:

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

Su un file:

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

Il merito va a la risposta di Cyrus qui .

1
Erik Nomitch

Una versione sed, funziona su 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

OP ha chiesto grep, ed è quello che CONSIGLIO; ma dopo aver provato a risolvere un problema con sed, per la cronaca, ecco una semplice soluzione:

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

o

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

Dipingerà main in rosso.

  • \E[31m: sequenza di inizio del colore rosso
  • \E[0m: segno di colore finito
  • &: il modello abbinato
  • /g: tutte le parole in una riga, non solo la prima
  • $'string' sono stringhe bash con caratteri di escape interpretati

Per quanto riguarda grep, funziona anche usando ^ (inizio riga) anziché $ (fine riga). Esempio:

egrep "^|main" testt.c

E solo per mostrare questo pazzo alias che NON CONSIGLIO, puoi anche lasciare le virgolette aperte:

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

tutto funziona! :) Non preoccuparti se dimentichi di chiudere la citazione, bash si ricorderà di te con un "carattere di linea continua".

0
Dr Beco