„Grep“, das hervorhebt, anstatt zu filtern

Ich habe mich gefragt, ob es ein Programm im allgemeinen Unix-Toolset wie grep gibt, das anstelle des Filterns der Zeilen, die eine Zeichenfolge enthalten, einfach dieselbe Eingabe ausgibt, aber die ausgewählte Zeichenfolge hervorhebt oder einfärbt.

Ich dachte daran, es selbst zu machen (sollte einfach genug sein), aber vielleicht existiert es bereits als Unix-Befehl.

Ich plane, es zum Überwachen von Protokollen zu verwenden, also würde ich so etwas tun:

tail -f logfile.log | highlight "error"

Normalerweise muss ich beim Überwachen von Protokollen eine bestimmte Zeichenfolge finden, aber ich muss auch wissen, was vor und nach der Zeichenfolge geschrieben wird, sodass das Filtern manchmal nicht ausreicht.

Gibt es so etwas?

Vielen Dank

Ziemlich viel hier beantwortet: stackoverflow.com/questions/981601/…
Das sieht für mich off-topic aus, da es nicht nach einer App fragt. Es wäre sicherlich besser auf unix.stackexchange.com gefragt

Antworten (14)

Das ist ein lustiger Trick dafür mit dem Grundbefehl grep. Es besteht aus der Verwendung von zwei Filtern: demjenigen, den Sie anwenden möchten, und einem Dummy-Filter, der mit allen Linien übereinstimmt, aber keine Hervorhebung erzeugt. Diese Dummy-Übereinstimmung kann entweder ^(Anfang der Zeile) oder $(Ende der Zeile) sein.

grep "^\|text" --color='always' file

oder

grep -E "^|text" --color='always' file

Siehe ein Beispiel:

$ cat a
hello this is 
some text i wanted
to share with you
$ grep "^\|text" --color='always' a
hello this is 
some text i wanted     # "text" is highlighted
to share with you
Es sieht so aus, als ob Sie nicht einmal brauchen ^oder $und "|text"funktioniert einfach so gut.

Es gibt ein Tool namens ack. Sie finden es unter http://beyondgrep.com und es ist tatsächlich ein Werkzeug jenseits von grep. Seine häufigste Verwendung ist die Besetzung dieser Rolle find . -name "*.java" --print | xargs grep clazzoder dergleichen. Denn das machen wir ständig.

Nur ack clazzund Sie erhalten die Ausgabe. Durchsucht die richtigen Dateien (versucht nicht, Binärdateien zu grep) und gibt auch eine schöne Farbausgabe.

Wenn Sie es mit der --passthruOption verwenden, wird der gesamte Eingabestrom gedruckt und die übereinstimmenden Bereiche farbig hervorgehoben.

--passthruDrucken Sie alle Zeilen, unabhängig davon, ob sie übereinstimmen oder nicht

Wie in der Dokumentation angegeben, -wird für die Datei STDIN verwendet:

Wenn Dateien oder Verzeichnisse angegeben sind, werden nur diese Dateien und Verzeichnisse überprüft. ack kann auch STDIN durchsuchen, aber nur, wenn keine Datei- oder Verzeichnisargumente angegeben sind oder wenn eines davon "-" ist.

Verzeihen Sie also den catMissbrauch ( und das Wortspiel - siehe unten ), Sie können es haben:

$ cat file | ack --passthru pattern
$ cat file | ack --passthru pattern -

Dies nimmt die Ausgabe der Pipe und sendet sie durch, ackwodurch alle Zeilen (mit --passthru) gedruckt werden, wobei das Muster hervorgehoben ist.

Dies ist genau das Tool, nach dem Sie suchen (und noch ein bisschen mehr). Es ist ein Standardpaket für viele Paketmanager. Siehe http://beyondgrep.com/install/ für Ihren Favoriten.

_ /|
\'oO'
=(___)=
   U ack --thpppt!

(Wenn Sie es nicht erkennen, das ist Bill the Cat , aber die Bildersuche könnte auch helfen - klicken Sie nicht auf das Miley Cyrus-Set)

Ack ist ein großartiges Tool, aber wie kann es seine gesamte Eingabe drucken, indem es einfach das Suchmuster hervorhebt? Es wird normalerweise als eine Form von Targeting verwendet grep -R, wie Sie erklären. Ich sehe nicht, wie es dem OP helfen kann.
@terdon Die --passthruOption druckt alle Zeilen und hebt die interessierenden Muster hervor. Ebenso kann man für die Arbeit an STDIN den Bindestrich als Dateinamen oder gar keine Dateiargumente verwenden.
Ich sehe, das macht Sinn. Da Sie sagten, es verhält sich wie grep, ging ich davon aus, dass es nur die passende Zeile drucken würde.
@terdon sein Standardmodus ist Grepy. Wie die Leute bei anderen Optionen darauf hingewiesen haben, kann man grep dazu bringen, alle Zeilen auszudrucken und den interessierenden Text hervorzuheben. ack muss dazu nicht ausgetrickst werden - es ist eine der Standardoptionen. Und danke für die klärende Bearbeitung.

Sie könnten das grep -CFlag verwenden, das n Kontextzeilen liefert, z. B. grep -C 3wird die 3 Zeilen vor und nach dem Spiel gedruckt. Es gibt auch -Bund -Afür vorher und nachher.

Wenn Sie bestimmte Zeichenfolgen regelmäßig hervorheben möchten, z. B. bestimmte Protokollformate, kann es sich lohnen, Python pygmentize mit einem benutzerdefinierten Lexer zu verwenden , da es auf Regex basiert, werden Sie erstaunt sein, wie einfach es ist . Letzteres hat auch den Vorteil, dass es plattformübergreifend ist, obwohl einige Terminals nicht sehr gut färben.

Ich bin ein Fan von hhighlighter von Paolo Antinori. https://github.com/paoloantinori/hhighlighter

Eine positive Seite dieses Befehls ist, dass er bis zu 10 Wörter mit einzigartigen Farben hervorheben kann. Leiten Sie einfach die Ausgabe eines Befehls hmit den hervorzuhebenden Wörtern an.

Bsp tail -f /var/log/somelog.log | h "ERROR"wird produzieren:

Demo-1


Einige Beispiele von seiner Seite:

Demo-2 Demo-3

Ich habe ein kleines Skript geschrieben, das jede Zeichenfolge einfärbt, die Sie ihm geben:

#!/usr/bin/env perl
use Getopt::Std;
use strict;
use Term::ANSIColor; 

my %opts;
getopts('hic:l:',\%opts);
    if ($opts{h}){
      print<<EoF; 
Use -l to specify the pattern(s) to highlight. To specify more than one 
pattern use commas. 

-l : A Perl regular expression to be colored. Multiple expressions can be
     passed as comma separated values: -l foo,bar,baz
-i : makes the search case sensitive
-c : comma separated list of colors;

EoF
      exit(0);
    }

my $case_sensitive=$opts{i}||undef;
my @color=('bold red','bold blue', 'bold yellow', 'bold green', 
           'bold magenta', 'bold cyan', 'yellow on_magenta', 
           'bright_white on_red', 'bright_yellow on_red', 'white on_black');
if ($opts{c}) {
   @color=split(/,/,$opts{c});
}
my @patterns;
if($opts{l}){
     @patterns=split(/,/,$opts{l});
}
else{
    $patterns[0]='\*';
}

# Setting $| to non-zero forces a flush right away and after 
# every write or print on the currently selected output channel. 
$|=1;

while (my $line=<>) 
{ 
    for (my $c=0; $c<=$#patterns; $c++){
    if($case_sensitive){
        if($line=~/$patterns[$c]/){
           $line=~s/($patterns[$c])/color("$color[$c]").$1.color("reset")/ge;
        }
    }
    else{
        if($line=~/$patterns[$c]/i){
          $line=~s/($patterns[$c])/color("$color[$c]").$1.color("reset")/ige;
        }
      }
    }
    print STDOUT $line;
}

Wenn Sie es colorin einem Verzeichnis speichern, das sich in Ihrem befindet, $PATHund es ausführbar machen ( chmod +x /usr/bin/color), können Sie das übereinstimmende Muster wie folgt einfärben:

echo -e "foo\nbar\nbaz\nbib" | color -l foo,bib 

Das wird produzieren:

  Geben Sie hier die Bildbeschreibung ein

Wie geschrieben, hat das Skript vordefinierte Farben für 10 verschiedene Muster. Wenn Sie ihm also eine durch Kommas getrennte Liste geben, wie ich sie im obigen Beispiel habe, wird jedes der übereinstimmenden Muster in einer anderen Farbe eingefärbt.

Ich habe vor einiger Zeit ein Programm geschrieben, um dies zu tun. Ich nenne es cgrep (für color grep).

Sie können es herunterladen, indem Sie den Codeabschnitt von hier in eine leere Datei kopieren: http://wiki.tcl.tk/38096

Machen Sie die Datei dann ausführbar und kopieren Sie sie in eines Ihrer regulären bin-Verzeichnisse.

Es ist in tcl geschrieben, also muss tcl installiert sein (8.5 und höher). Aber die meisten Linux-Distributionen hätten tcl sowieso installiert, da viele Software es verwendet (gitk, Kernel-Konfiguration, erwartet usw.).

Die Syntax für die Färbung ist einfach: regex option option ... Sie können so viele Regex haben, wie Sie möchten. Hier ist ein Beispiel, das Fehler rot und Warnungen gelb einfärben würde:

tail -f logfile | cgrep '^.*WARNING.*$' -fg yellow '^.*ERROR.*$' -fg red -bg yellow

Der einfachste Weg sieht meiner Meinung nach so aus:

tail -f logfile.log | grep -e 'error' -e '**'

Geben Sie hier die Bildbeschreibung ein

Es muss nichts installiert werden.

Nun, ich verwende Fedora 21 und wenn ich tippe

grep -E \|kk rs.c

es wird den gesamten Inhalt der Datei "rs.c" ausgeben, während alle Vorkommen von "kk" hervorgehoben werden.

Das ist im Grunde dasselbe wie die Antwort von arielCo .
@Izzy: Die Syntax ist jedoch kürzer, daher würde ich sagen, dass sie sich als eine andere gültige Antwort qualifiziert.
@NicolasRaoul deshalb habe ich damals nur einen Kommentar hinterlassen (aber nicht gemeldet). Im Grunde hatte ich gehofft, dass sich das Poster etwas ausdehnt ;)

Sie können diesen Befehl verwenden

grep --color --context=1000

Oder kürzer

grep --col -1000

erklärthell.com - grep --color --context

Ein einfacher Trick besteht darin, auch einen leeren String oder den Anfang einer Zeile zu finden; Beides führt zu einer Nulllängenübereinstimmung für alle Zeilen:

grep --color -e 'REGEXP' -e ''
grep --color -e 'REGEXP' -e ^

Oder (erweiterte Regexp-Syntax):

grep --color -E 'REGEXP|'
egrep --color 'REGEXP|'
Würde die erste Variante nicht auch die Ausgabe filtern REGEX? Ich habe es gerade versucht, und es funktioniert. Das entspricht also nicht den Anforderungen (nur markieren, nicht filtern). Aber die zweite Variante tut tatsächlich das, was das OP angefordert hat (verifiziert;).
Ja, das macht jetzt Sinn :) Filtern Sie nach REGEX(hebt diesen Begriff hervor) und nach "nichts" (was "überall" ist). Darf ich vorschlagen, dass Sie diese kleine Erklärung einfügen (auch um klarzustellen, was sie tut), und dann löschen wir unsere Kommentare (zur Bereinigung)? Vielen Dank! Inzwischen +1 von mir :)
Wird gemacht, aber Fedorqui hat im Wesentlichen die gleiche Antwort oben gegeben (ich glaube, ich habe sie nicht gesehen, als ich meine gepostet habe).
Muss zugeben, dass ich das auch nicht gesehen habe ... (Hinweis: Es gibt kein "oben" oder "unten", da die Reihenfolge der Antworten davon abhängt, welchen Filter Sie eingestellt haben ;)

Verwenden Sie less. Die Suchzeichenfolge, die von gefunden wird, /ist ein regulärer Ausdruck, und die Vorkommen werden hervorgehoben.

In meiner .bashrc habe ich diese Funktion. Ich nenne es cgrep, aber ich gebe ihm hier einen etwas treffenderen Namen.

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

Ich finde das zum Beispiel nützlich, um Protokolle zu verfolgen, wo ich ein Schlüsselwort hervorheben, aber alles sehen möchte, was vor sich geht.

tail -f /var/log/SOMELOG | highlight KEYWORD
Gutschrift: Ich habe das "^|" Idee aus der ausgewählten Antwort von @fedorqui. Vielen Dank :)

Sie können Ihre Ausgabe einfach weiterleiten an:

sed "s/\([Ee][Rr][Rr][Oo][Rr]\)/`tput rev`\1`tput rmso`/"

Hier verwende ich einen regulären Ausdruck, der mit „error“, „ERROR“, „ErRoR“ usw. in allen 32 möglichen Variationen übereinstimmt.

Ich habe die folgende Funktion in meinem definiert ~/.zshrc:

hl () {
    sed s/$1/$'\e[1;31m'\&$'\e[0;m'/
}

Verwenden Sie es mit tail -f logfile.log | hl "error". Es fügt vor dem hervorgehobenen Wort eine Escape-Sequenz für Hellrot hinzu und setzt nach dem Wort auf keine Farbe zurück. Weitere Farbcodes finden Sie hier: http://tldp.org/HOWTO/Bash-Prompt-HOWTO/x329.html