Überzeuge grep, alle Zeilen auszugeben, nicht nur die mit Übereinstimmungen

121

Angenommen, ich habe die folgende Datei:

$ 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

Standardmäßig wird grepjede Zeile zurückgegeben, die den Suchbegriff enthält:

$ grep test test

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

Durch Übergeben des --colorParameters an grepwird der Teil der Zeile hervorgehoben, der dem Suchausdruck entspricht, es werden jedoch nur Zeilen zurückgegeben, die den Ausdruck enthalten. Gibt es eine Möglichkeit, grepjede Zeile in der Quelldatei auszugeben, aber die Übereinstimmungen zu markieren?

Mein derzeitiger schrecklicher Hack, um dies zu erreichen (zumindest bei Dateien, die nicht mehr als 10000 aufeinanderfolgende Zeilen ohne Übereinstimmungen enthalten), ist:

$ grep -B 9999 -A 9999 test test

Screenshot der beiden Befehle

Wenn grepdies nicht möglich ist, gibt es ein anderes Befehlszeilentool, das dieselbe Funktionalität bietet? Ich habe damit herumgespielt ack, aber es scheint auch keine Option dafür zu geben.

Michael Mrozek
quelle
1
Mögliches Cross-Site-Duplikat von: stackoverflow.com/questions/981601/… Die beste Antwort ist für beide gleich.
Ciro Santilli
1
Sie können -C 9999anstelle von verwenden. -A 9999 -B 9999Ich mache immer:grep -C 9999 pattern file
Neo

Antworten:

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

Was wir hier machen, ist die Übereinstimmung mit dem $Muster und dem Testmuster, offensichtlich $gibt es nichts zu färben, so dass nur das Testmuster Farbe bekommt. Das -Eschaltet gerade den erweiterten Regex-Abgleich ein.

Sie können leicht eine Funktion daraus erstellen:

highlight () { grep --color -E "$1|$" "${@:1}" ; }
jacksonh
quelle
14
Das ist verdammt geil!
gvkv
3
Und als Funktion: highlight () { grep --color -E "$1|$" $2 ; }. Verwendung:highlight test yourfile
Stefan Lasiewski
2
@ StefanLasiewski: "$2"sollte auch zitiert werden.
Dennis Williamson
6
Besser wäre: highlight () { grep --color -E "$1|$" "$@" }das erlaubt Dateien mit Leerzeichen im Namen und mehrere Dateien.
Mike DeSimone
15
@MikeDeSimone - Das wird aber auch "$1"in den Dateien haben. Verwenden Siehighlight () { grep --color -E "$1|$" "${@:1}" }
Chris Down
40
ack --passthru --color string file

Verwenden Sie für Ubuntu und Debian ack-grep anstelle von ack

ack-grep --passthru --color string file
Dennis Williamson
quelle
1
Oh, das steht ganz offensichtlich auf der Manpage. Ich bin blind. Danke
Michael Mrozek
das muster für grap kann explizit mit angegeben werden --regexp string; das ack / ack-grep-äquivalent ist--match string
Rhabarber
So simulieren Sie ack --passthrumit Perl:grep_passthrough () { ! perl -ne "print; \$e ||= /$@/; END{{exit \$e}}"; }
Lucas Cimon
ack --passthruFunktioniert auch auf Streams! Zum Beispielifconfig | ack --passthru inet
Honkaboy
13

Ein anderer Weg , dies zu tun richtig und portabel mit grep(außer mit zwei regulären Ausdrücke mit Wechsel , wie in der akzeptierten Antwort) über die Null - Muster (bzw. Null - String).
Es sollte mit beiden -Eund -FSwitches gleich gut funktionieren, da laut Standard :

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

und

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

Es geht also nur ums Laufen

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

bzw.

grep -F -e '' -e 'string' infile
don_crissti
quelle
1
Oder einfach grep -F -e '' -e 'string'.
Stéphane Chazelas
Es funktioniert für mich mit GNU grep 2.25, busybox grep und dem Erbstück-Toolchest.
Stéphane Chazelas
OK, meine schlechte, seq 3 | grep -F -e '' -e 2gibt nur 2 in 2,27 (und 2,26, aber nicht 2,25 und nicht im Git-Kopf). Nur mit -F(nicht ohne oder mit -E). IOW, nur 2.26 und 2.27 scheinen den Bug zu haben und nur mit -F.
Stéphane Chazelas
Beachten Sie, dass seq 3 | grep -F -e '' -e '' -e 2 dies auch mit 2.27
Stéphane Chazelas am
1
Die in dieser Antwort angegebene Methode ist einfach, korrekt und scheint recht schnell zu sein . Wie Sie sagen , funktioniert es automatisch -F, so dass Sie sich keine Gedanken mehr darüber machen müssen, in welchen Zeichen sie vorkommen string. Sie möchten vielleicht erwähnen --color; Wenn diese Antwort auf der Seite auftaucht (wenn sie nach Stimmen sortiert ist), werden möglicherweise mehr Personen sie vor den anderen Antworten lesen.
Eliah Kagan
11

Ich habe die folgende Funktion, die ich für solche Dinge benutze:

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

Intern sieht es irgendwie hässlich aus, es ist schön und einfach zu bedienen, wie folgt:

cat some_file.txt | highlight some_word

oder, für ein etwas realeres Beispiel:

tail -f console.log | highlight ERROR

Sie können die Farben nach Belieben ändern (was bei grep möglicherweise schwierig ist - da bin ich mir nicht sicher), indem Sie die Werte für 1und 31und 43(danach \e[) in unterschiedliche Werte ändern . Die Codes zu verwenden sind alle über den Ort , aber hier ist eine kurze Einführung: die 1 bolds der Text, das 31macht es rot, und das 43gibt einen gelben Hintergrund. 32oder 33würde verschiedene Farben haben, und 44oder 45würde verschiedene Hintergründe haben: Sie bekommen die Idee. Sie können es sogar zum Blinken bringen (mit einem 5), wenn Sie dazu neigen.

Dies verwendet keine spezielle Perl - Module und Perl ist fast allgegenwärtig, also würde ich erwarten , dass es so gut wie überall zu arbeiten. Die grep-Lösung ist sehr clever, aber der --color-Schalter für grep ist nicht überall verfügbar. Ich habe diese Lösung beispielsweise gerade auf einer Solaris-Box mit bash und einer anderen mit ksh sowie auf meinem lokalen Mac OS X-Computer mit zsh ausprobiert. Alles hat gut funktioniert. Solaris erstickte jedoch an der grep --colorLösung.

Außerdem ist ack großartig und ich empfehle es jedem, der es noch nicht entdeckt hat, aber ich hatte einige Probleme, es auf einigen der vielen Server zu installieren, auf denen ich arbeite. (Ich vergesse, warum: Ich denke, im Zusammenhang mit Perl-Modulen ist es erforderlich.)

Da ich nicht glaube , habe ich jemals gearbeitet auf einer Unix - Box , die nicht hat Perl installiert ist (mit Ausnahme von Embedded-Systemen des Typs, Linksys - Router, und so) würde ich sagen , dass dies so ziemlich eine universell einsetzbare Lösung ist .

Bilderstürmer
quelle
3

Anstelle von Grep können Sie auch Less verwenden:

less file

Suche so: /pattern Enter

Dieser Wille:

  1. zur ersten übereinstimmenden Zeile blättern
  2. gib jede Zeile ab dort aus
  3. Markieren Sie alle Übereinstimmungen

So blättern Sie zur nächsten übereinstimmenden Zeile: n

So blättern Sie zur vorherigen übereinstimmenden Zeile: N

So schalten Sie die Hervorhebung um: Esc u

Sie können auch die Hervorhebungsfarbe ändern, wenn Sie möchten.

Steven Penny
quelle
2

Du kannst es versuchen:

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

Nicht sehr portabel, und selbst wenn Perl installiert ist, müssen Sie möglicherweise ein anderes Modul herunterladen. Außerdem färbt es die gesamte Zeile und nicht nur das Suchwort.

gvkv
quelle
2

ripgrep

Verwenden Sie ripgrepmit seinem --passthruParameter:

rg --passthru pattern file.txt

Es ist eines der schnellsten Grepping-Tools , da es auf Rusts Regex-Engine aufbaut , die endliche Automaten, SIMD und aggressive wörtliche Optimierungen verwendet, um die Suche sehr schnell zu machen.

--passthru - Drucken Sie sowohl übereinstimmende als auch nicht übereinstimmende Zeilen.

Eine andere Möglichkeit, einen ähnlichen Effekt zu erzielen, besteht darin, das Muster so zu ändern, dass es mit der leeren Zeichenfolge übereinstimmt. Wenn Sie beispielsweise mit suchen, rg foowird rg "^|foo"stattdessen mit jede Zeile in jeder durchsuchten Datei ausgegeben, aber nur Vorkommen von foo werden hervorgehoben. Dieses Flag aktiviert dasselbe Verhalten, ohne dass das Muster geändert werden muss.

Kenorb
quelle
1

Es gibt einen viel einfacheren Weg, dies für GNU grep zu tun, aber ich denke nicht, dass es portabel ist (dh BSD grep):

In einer Pipe:

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

In einer Datei:

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

Hier geht es um Cyrus 'Antwort .

Erik Nomitch
quelle
1
Dies ist keine so gute Antwort, wie Sie (und Cyrus) denken. Dies bewirkt, dass die gesamte Datei als einzelne Zeile behandelt wird. Daher (1) , wenn die Datei sehr groß ist, kann es eine Möglichkeit sein , aus dem Speicher ausgeführt wird , und (2) wenn die Datei nicht das Muster enthält überhaupt , dann wird nichts ausgegeben. Und du hast recht; es ist nicht allgemein verfügbar. (Aber auch das --colorist kein Standard .)
G-Man
Auf welcher Version von grep wird dies unterstützt? Auf grep 2.5.4, -z scheint nicht verfügbar ...
Alex
1

Keine der bisher gegebenen Antworten bietet eine tragbare Lösung.

Hier ist eine portable 1 Shell - Funktion ich bereits geschrieben in einem geschlossenen als doppelte Frage , die nicht Nicht - Standard - Tools oder Nicht - Standard - Verlängerungen erfordert mit perl, ack, ggrep, gsed, bashund die Gleichen , sondern braucht nur ein POSIX - Shell und die POSIX - Pflicht Dienstprogramme sedund printf:

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

Du kannst es so benutzen:

grepc string_to_search [file ...]

Die Hervorhebungsfarbe kann mithilfe eines der folgenden Codes im sed-Befehlsargument angepasst werden (32 m sind hier grün):

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

1 Solange Ihr Terminal ANSI-Farben-Escape-Sequenzen unterstützt.

jlliagre
quelle
0

Eine sedVersion, die auf beiden bashund funktioniert 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" "$@"
}
yurenchen
quelle
0

OP gefragt grep, und das ist, was ich EMPFEHLEN ; Aber nachdem Sie sich bemüht haben, ein Problem zu lösen sed, finden Sie hier eine einfache Lösung:

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

oder

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

Wird mainin rot malen .

  • \E[31m : rote Farbe Startreihenfolge
  • \E[0m : fertige Farbmarke
  • & : das passende Muster
  • /g : alle Wörter in einer Zeile, nicht nur die ersten
  • $'string' Bash-Strings mit Escape-Zeichen werden interpretiert

In Bezug auf grep funktioniert es auch mit ^(Zeilenanfang) anstelle von $(Zeilenende). Beispiel:

egrep "^|main" testt.c

Und nur um diesem verrückten Alias ​​zu zeigen, dass ich es NICHT EMPFEHLE , können Sie sogar die offenen Zitate lassen:

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

Alle Arbeit! :) Mach dir keine Sorgen, wenn du vergisst, das Zitat zu schließen, wird dich bash mit einem "fortlaufenden Linienzeichen" erinnern.

Dr. Beco
quelle