Mehrfarbiges Grep

30

Ich versuche, jeden grep-Befehl zu veranlassen, die Ergebnisse in einer anderen Farbe hervorzuheben. Ich kann es manuell mit einer Zeile wie dieser machen:

ls -l GREP_COLORS='mt=01;32' grep c | GREP_COLORS='mt=01;31' grep o | GREP_COLORS='mt=01;34' grep n | GREP_COLORS='mt=01;36' grep f

Jedes cZeichen wird grün hervorgehoben und jedes oZeichen wird rot hervorgehoben, etc ...

Damit dieses Beispiel funktioniert, müssen Sie sicherstellen, dass --color=alwaysIhre grep-Befehle immer verfügbar sind. Ich habe dies .bashrc so eingestellt, dass grep immer Farben hat:

export GREP_OPTIONS='--color=always'


Ich versuche, diese Funktionalität mit einem Alias ​​zu versehen, damit ich jedes Mal grepeinen anderen GREP_COLORSWert aufrufen kann . Ich verstehe die Berücksichtigung mehrerer Shells für jedes neue Pipe-Grep und versuche, dies zu überwinden, indem ich einige Dateien (eine für jede Farbe) erstelle, um anzuzeigen, dass sie bereits verwendet wurden.

Ich habe einige Versuche unternommen, aber seltsamerweise scheint dieser "am besten" zu funktionieren. Ich habe das in meinem .bashrc:

alias mg="mygrep"
mygrep(){
    # define possible colors
    COLORS=("01;32" "01;31" "01;34" "01;36")
    COUNTER=0
    NUM=0
    # as long as the color has already been used, keep searching
    while [ -f /home/lior/Desktop/mygrep_$NUM ]; do
        # get a random index
        let NUM=`shuf --input-range=0-$(( ${#COLORS[*]} - 1 )) | head -1`
        wait ${!}
        $(( COUNTER+=1 ))
        if [ "$COUNTER" -ge ${#COLORS[@]} ]; then
            # remove all color locks
            rm /home/lior/Desktop/mygrep_*
            wait ${!}
        fi
    done
    # mark this color as used
    touch /home/lior/Desktop/mygrep_$NUM
    wait ${!}

    # lets go!
    GREP_COLORS="mt=${COLORS[$NUM]}" grep "$@"
}

Ich benutze diesen Alias ​​wie folgt:

ll | mg c | mg o | mg n | mg f

Die Ergebnisse sind ziemlich cool. Es gibt jedoch einige Fehler, die sich jedes Mal geringfügig unterscheiden. Hier sind ein paar Screenshots:

Sieht so aus, als ob die Shell jeden Pipe-Befehl durchläuft und die vorherige Funktion ihre Ausführung noch nicht beendet hat. Es wird versucht, nicht mehr vorhandene Dateien zu entfernen. Ich bin mir nicht sicher, woher diese anderen command not foundFehler kommen.

Wie Sie sehen, habe ich einige waitBefehle eingegeben, um die Dateimanipulation zu beenden, aber dies scheint nicht allzu gut zu funktionieren. Eine andere Sache, die ich bereits ausprobiert habe, ist die Verwendung von Shared Memory, die /dev/shmjedoch zu ähnlichen Ergebnissen führt.

Wie würde ich vorgehen, um die gewünschten Ergebnisse zu erzielen?

Hinweis:

Ich bin auf der Suche nach Antworten, die einfach den Befehl grep umbrechen, da er viele Funktionen enthält, die ich verwenden möchte, und beabsichtige, andere Logik zwischen die Pipes einzufügen, sodass ich nicht alle Suchbegriffe auf einmal bereitstellen möchte. Ich bin auch nicht auf der Suche nach anderen "grep like" Tools. Sorry an @terdon , der bereits einen tollen Perl-Vorschlag gepostet hat.

Lix
quelle
Ihr erstes Beispiel stimmt nicht mit dem überein, was Sie im verbleibenden Teil erklären, nur sagen.
Bernhard
@bernhard Ich verstehe nicht , was du meinst .. Meine Absicht ist mein Alias als Teil eines größeren Befehl Leitungen nutzen ... Bitte lassen Sie mich wissen , was Widerspruch Sie sprechen von ...
Lix
Ich dachte, Sie wollten Ihren Alias ​​auch außerhalb von Pipes verwenden. Wie auch immer, dein erstes Beispiel funktioniert bei mir nicht. Hast du es versucht alias mg="mygrep; grep"?
Bernhard
@Bernhard - Ich arbeite an einer Ubuntu 12.04 Box. Es würde mich nicht wundern, wenn es kleine Unterschiede gäbe ... Ich habe Ihren Vorschlag ausprobiert, das Problem dabei ist, dass mygrep;sich ein neuer Befehl in sich verwandelt und der Datenstrom verloren geht. Die eingehende Pipe von der lswürde weitergeleitet mygrep;und nicht zu grep. Zumindest verstehe ich das so.
Lix
@Bernhard - Ah .. ich glaube ich weiß warum es bei dir nicht geklappt hat. Sie müssen sicherstellen, dass Sie --color=alwaysalle Ihre grep-Befehle aktiviert haben. Ich habe das global in meinem festgelegt .bashrc. Ich habe das in der Post bearbeitet.
Lix

Antworten:

6

Hier ist ein anderer Ansatz. Ich habe ein kleines Perl-Skript, das ich bereits in einer anderen Antwort veröffentlicht habe, die die vom Benutzer bereitgestellten Muster in verschiedenen Farben hervorhebt. Eine leicht modifizierte Version des Skripts sieht folgendermaßen aus grep:

#!/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_blue', 
       'bright_white on_yellow', '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=<>) 
{ 
    my $want=0;
    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;
           $want++;
        }
    }
    else{
        if($line=~/$patterns[$c]/i){
          $line=~s/($patterns[$c])/color("$color[$c]").$1.color("reset")/ige;
          $want++;
        }
      }
    }
print STDOUT $line if $want>0;
}

Wenn Sie dieses Skript cgrepirgendwo in Ihrem speichern PATHund ausführbar machen, können Sie bis zu 10 verschiedene Muster angeben, von denen jedes in einer anderen Farbe gedruckt wird:

Bildbeschreibung hier eingeben

$ cgrep -h
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;
terdon
quelle
5

Jeder Aufruf von grepin einer Pipe wird in einer separaten Shell ausgeführt, sodass Sie einen Status zwischen ihnen übergeben müssen. Die folgende Lösung ist eine einfache Möglichkeit, dies mit einer Datei zu tun, die den Farbindex enthält, und einer Sperrdatei, die sicherstellt, dass gleichzeitige Aufrufe nicht denselben Wert lesen:

#!/usr/bin/env bash
color_index_file=~/.gitcolor
color_index_lock_file=/tmp/$(basename $0)

colors=()
for index in {31..34}
do
    colors+=("01;$index")
done

until mkdir "$color_index_lock_file" 2>/dev/null
do
    :
done

color_index=$(($(cat "$color_index_file" || echo 0) + 1))

if [[ $color_index -ge ${#colors[@]} ]]
then
    color_index=0
fi

printf "$color_index" > "$color_index_file"
rmdir "$color_index_lock_file"

GREP_COLORS="mt=01;${colors[$color_index]}" grep --color=always "$@"

Testen Sie unter der Annahme, dass Sie Ihre Kopie benannt haben, cgrepund platzieren Sie sie auf Ihrer PATH:

echo foobarbaz | cgrep foo | cgrep bar | cgrep baz
l0b0
quelle
Die einzigen Variablen, die wirklich gepflegt werden müssen, sind COLOR_INDEXund GREP_COLORS. Ich habe versucht, diese am Ende der Funktion ohne Erfolg zu exportieren. Ist es das, was du meintest? Einfach zu haben export VAR, oder?
Lix
Oh - und ja ... dummer Tippfehler mit COLOR_TOGGLE. Vielen Dank für den Fang :)
Lix
1
@ l0b0 Das Exportieren funktioniert auch bei mir nicht, muss erst mal runterstimmen, bis es die Frage wirklich beantwortet.
Bernhard
@Bernhard Funktioniert das für dich?
l0b0
Danke für deinen Beitrag! Ich habe Ihren grep "$@"Vorschlag aufgenommen - der den Alias ​​aussortiert, um die Funktion auszuführen, und dann grep.
Lix
1

Wenn Sie gut mit regulären Ausdrücken umgehen können, sollten Sie grc und grcat ausprobieren. grc ruft grcat auf.

grcat verwendet Konfigurationsdateien, in denen Sie reguläre Ausdrücke hinzufügen können, um dem Text zu entsprechen, der in jeder Farbe angezeigt werden soll. Es gibt auch eine Reihe anderer Optionen. Standardmäßig werden Systemprotokolldateien eingefärbt.

Je nachdem, was Sie für Ihr endgültiges Skript im Sinn haben, können Sie Ihre Ausgabe möglicherweise mit nur einem Befehl einfärben.

Der Trick besteht darin, die regulären Ausdrücke für jedes "Feld" in Ihrer Datenquelle korrekt anzugeben. Dies ist viel einfacher, wenn Ihre Daten eine relativ einheitliche Struktur haben.

Das letzte Mal, als ich es ausprobiert habe, bin ich nicht weit gekommen, aber ich kann es vielleicht noch einmal versuchen, weil ich ein bisschen besser in Regex bin als damals.

Es gibt auch den Befehl tput, mit dem Sie Informationen (z. B. Farbänderungen) direkt an Ihr Endgerät senden können.

Beide Ansätze werden im folgenden Beitrag behandelt. Es handelt sich um den Befehl find, kann jedoch auf die Ausgabe eines beliebigen Befehls angewendet werden.

Farbige FIND-Ausgabe?

Joe
quelle