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


121

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, greprestituisce 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 --colorparametro a grepsi 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 grepl'output di 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

Schermata dei due comandi

Se ciò grepnon è possibile, esiste un altro strumento da riga di comando che offre le stesse funzionalità? Ho armeggiato ack, ma non sembra avere nemmeno un'opzione per questo.


1
Possibile duplicato su più siti di: stackoverflow.com/questions/981601/… La risposta migliore è la stessa su entrambi.
Ciro Santilli 16 改造 中心 法轮功 六四 事件

1
Puoi usare -C 9999al posto di -A 9999 -B 9999.Faccio sempre:grep -C 9999 pattern file
neo

Risposte:


184
grep --color -E "test|$" yourfile

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

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

highlight () { grep --color -E "$1|$" "${@:1}" ; }

14
È fantastico!
gvkv,

3
E come una funzione: highlight () { grep --color -E "$1|$" $2 ; }. Utilizzo:highlight test yourfile
Stefan Lasiewski,

2
@StefanLasiewski: "$2"dovrebbe anche essere citato.
Dennis Williamson,

6
Meglio potrebbe essere: highlight () { grep --color -E "$1|$" "$@" }che consente ai file con spazi bianchi nei loro nomi e più file.
Mike DeSimone,

15
@MikeDeSimone - Ma questo avrà anche "$1"nei file. Usahighlight () { grep --color -E "$1|$" "${@:1}" }
Chris Down il

40
ack --passthru --color string file

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

ack-grep --passthru --color string file

1
Oh, questo è abbastanza evidente nella pagina man; Sono cieco. Grazie
Michael Mrozek

il pattern per grap può essere specificato esplicitamente con --regexp string; l'equivalente ack / ack-grep è--match string
Rhubbarb

Per simulare ack --passthrucon perl:grep_passthrough () { ! perl -ne "print; \$e ||= /$@/; END{{exit \$e}}"; }
Lucas Cimon

ack --passthrufunziona anche su stream! Ad esempio,ifconfig | ack --passthru inet
honkaboy

13

Un altro modo per fare questo correttamente e portabile con grep(oltre all'utilizzo di due regex un'alternanza come nella risposta accettata) è tramite il modello nullo (e stringa rispettivamente nullo).
Dovrebbe funzionare ugualmente bene con entrambi -Ee -Fswitch poiché, 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

1
O semplicemente grep -F -e '' -e 'string'.
Stéphane Chazelas,

Funziona per me con GNU grep 2.25, busybox grep e quello cimelio più ricco di strumenti.
Stéphane Chazelas,

OK, mio ​​male, seq 3 | grep -F -e '' -e 2produce solo 2 in 2.27 (e 2.26, ma non 2.25, e non nella testa git). Solo con -F(non senza o con -E). IOW, solo 2.26 e 2.27 sembrano avere il bug e solo con -F.
Stéphane Chazelas,

Si noti che seq 3 | grep -F -e '' -e '' -e 2 sembra funzionare anche con 2.27
Stéphane Chazelas il

1
Il metodo indicato in questa risposta è semplice, corretto e sembra abbastanza veloce . Come dici tu , funziona automaticamente con -F, alleviando la necessità di preoccuparsi di quali personaggi compaiono string. Potresti voler menzionare --color; quando questa risposta si sposta sulla pagina (se vista dai voti), più persone potrebbero finire per leggerla prima delle altre risposte.
Eliah Kagan,

11

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 ne sono sicuro) cambiando 1e 31e 43(dopo \e[) in valori diversi. I codici da utilizzare sono tutti sopra il luogo , ma qui è una rapida introduzione: il 1 grassetto il testo, la 31rende rosso, e la 43dà uno sfondo giallo. 32o 33sarebbero colori diversi e 44o 45sarebbero sfondi diversi: avrai l'idea. Puoi persino farlo lampeggiare (con a 5) se sei così incline.

Questo non utilizza alcun modulo Perl speciale e Perl è quasi onnipresente, quindi mi aspetto che funzioni praticamente 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. grep --colorTuttavia, Solaris ha soffocato la soluzione.

Inoltre, ack è fantastico e lo consiglio a chiunque non lo abbia 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 lavorato su una scatola Unix su cui non era installato Perl (ad eccezione dei sistemi di tipo incorporato, dei router Linksys e simili), direi che questa è praticamente una soluzione universalmente utilizzabile .


3

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 il colore di evidenziazione, se lo desideri.


2

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

ripgrep

Utilizzare ripgrepcon il suo --passthruparametro:

rg --passthru pattern file.txt

È uno degli strumenti più veloci per il grepping , poiché è basato sul motore regex di Rust che utilizza automi finiti, SIMD e ottimizzazioni letterali aggressive per rendere la ricerca molto veloce.

--passthru - Stampa sia linee corrispondenti che non corrispondenti.

Un altro modo per ottenere un effetto simile è modificando il modello in modo che corrisponda alla stringa vuota. Ad esempio, se si sta effettuando una ricerca utilizzando, rg fooutilizzando rg "^|foo"invece verrà emessa 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.


1

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

In una pipa:

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

Su un file:

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

Il merito va alla risposta di Cyrus qui .


1
Questa non è una buona risposta come tu (e Cyrus) pensate. Ha l'effetto di trattare l'intero file come una singola riga. Pertanto, (1) se il file è molto grande, ci può essere la possibilità di corto di memoria, e (2) se il file non contiene il modello affatto , allora nulla sarà uscita. E hai ragione; non è universalmente disponibile. (Ma poi di nuovo, --colornon è nemmeno standard .)
G-Man,

Su quale versione di grep è supportato? Su grep 2.5.4, -z non sembra disponibile ...
Alex

1

Nessuna delle risposte fornite finora fornisce una soluzione portatile .

Ecco un portatile 1 funzione di shell ho già postato in un ambiente chiuso come domanda duplicato che non richiede utensili standard non o estensioni non standard forniti con perl, ack, ggrep, gsed, bashe simili, ma necessita solo un guscio POSIX ei POSIX utilità obbligatorie sede printf:

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

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 terminale supporta sequenze di escape colori ANSI.


0

Una sedversione, funziona su entrambi bashe 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" "$@"
}

0

OP richiesto grep, ed è quello che CONSIGLIO ; ma dopo aver provato a risolvere un problema 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à mainin rosso.

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

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

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.