Wie färbt man nur einige Schlüsselwörter für ein Bash-Skript ein?

10

Ich führe einen Unit-Test-Code aus. Der Unit-Test-Code gibt normalen Text aus. Da der Text viel enthält, möchte ich für den Benutzer wichtige Schlüsselwörter hervorheben.

In diesem Fall lauten die Schlüsselwörter "PASS" und "FAIL".

Wie färbt man "PASS" grün und "FAIL" rot?

Trevor Boyd Smith
quelle
Haben Sie darüber nachgedacht, stdout / stderr von Tests zu unterdrücken, die bestanden wurden, und stdout / stderr nur für fehlgeschlagene Tests zu drucken? PHPUnit tut dies oder ist dafür konfigurierbar. Ich habe festgestellt, dass dieser Ansatz ziemlich gut funktioniert, YMMV.
Clayton Stanley

Antworten:

8

supercat scheint zu tun, wonach Sie suchen.

Paket: Superkatze
Description-de: Programm, das Text für Terminals und HTML einfärbt
 Supercat ist ein Programm, das Text basierend auf übereinstimmenden regulären Farben einfärbt
 Ausdrücke / Zeichenfolgen / Zeichen. Supercat unterstützt auch die HTML-Ausgabe
 als Standard-ASCII-Text. Im Gegensatz zu einigen Text-Colorizing-Programmen, die
 existieren, erfordert Supercat nicht, dass Sie ein Programmierer sein müssen, um
 Kolorierungsregeln erstellen.
Homepage: http://supercat.nosredna.net/

Es scheint keine Möglichkeit zu geben, anzugeben, was in der Befehlszeile eingefärbt werden soll. Sie müssen eine Konfigurationsdatei angeben.

Ich erinnere mich an ein Programm namens "hilite" oder "hl", das Text hervorhob, der einem Muster entsprach (wie grep --colour, aber auch nicht übereinstimmende Linien anzeigte), aber ich konnte ihn nicht finden, als ich danach suchte.

Schließlich kann GNU grepverwendet werden, um Muster hervorzuheben - es kann jedoch nur eine Farbe verwendet werden (dh Sie können PASS nicht in Grün und FAIL in Rot haben, beide werden mit derselben Farbe hervorgehoben).

Führen Sie Ihre Daten wie folgt durch:

egrep --color "\b(PASS|FAIL)\b|$"

In diesem Beispiel wird egrep (aka grep -E) verwendet, aber auch -Gregulärer regulärer Ausdruck, -Ffester String und -PPCRE funktionieren.

Alle Übereinstimmungen werden hervorgehoben. Die Standardeinstellung ist rot, oder legen Sie die env-Variable GREP_COLOR fest.

Der Schlüssel zu dieser Arbeit ist, dass das Finale |$im Muster mit dem Zeilenende übereinstimmt (dh alle Zeilen stimmen überein), sodass alle Zeilen angezeigt (aber nicht eingefärbt) werden.

Das \bsind Worte , Grenzmarkierungen , so dass sie paßt zB FAIL aber nicht AUSFALL. Sie sind nicht erforderlich. Entfernen Sie sie daher, wenn Sie Teilwörter abgleichen möchten.

Hier ist das Beispiel-Wrapper-Skript für Supercat, das ich gestern geschrieben habe. Es funktioniert, aber beim Schreiben habe ich festgestellt, dass Supercat keine Option für Suchvorgänge ohne Berücksichtigung der Groß- und Kleinschreibung hat. IMO, das macht das Programm deutlich weniger nützlich. Es hat das Skript jedoch stark vereinfacht, da ich keine '-i'-Option schreiben musste :)

#! /bin/bash 

# Requires: tempfile from debian-utils, getopt from util-linux, and supercat

SCRIPTNAME=$(basename $0)
CFGFILE=$(tempfile -p spc)

usage() {
  cat <<__EOF__
Highlight regexp patterns found on stdin or files specified on command
line with specified colours.

Usage: $SCRIPTNAME [ --colour "pattern" ...] [FILE]

Options:

        -k,--black   regexp
        -r,--red     regexp
        -g,--green   regexp
        -y,--yellow  regexp
        -b,--blue    regexp
        -m,--magenta regexp
        -c,--cyan    regexp
        -w,--white   regexp

Example:

    run-script.sh | $SCRIPTNAME --green PASS --red FAIL

__EOF__
  exit 0
}


# Format definition from the spc man page:
#1234567890123456789012345678901234567890123456789012345
#HTML Color Name      Col A N T RE / String / Characters
FMT="%-20s %3s %1s %1s %1s (%s)\n"

add_color_to_config() {
  COLOR="$1"
  PATTERN="$2"

  printf "$FMT" "$COLOR" "$COLOR" - 0 r "$PATTERN" >> "$CFGFILE"
}


# uses the "getopt" program from util-linux, which supports long
# options. The "getopts" built-in to bash does not.
TEMP=$(getopt \
       -o 'hk:r:g:y:b:m:c:w:' \
       -l 'help,black:,red:,green:,yellow:,blue:,magenta:,cyan:,white:' \
       -n "$0" -- "$@")

if [ $? != 0 ] ; then echo "Terminating..." >&2 ; exit 1 ; fi

eval set -- "$TEMP"

while true ; do
    case "$1" in
        -k|--bla*)       add_color_to_config blk "$2" ; shift 2 ;;
        -r|--red)        add_color_to_config red "$2" ; shift 2 ;;
        -g|--gre*)       add_color_to_config grn "$2" ; shift 2 ;;
        -y|--yel*)       add_color_to_config yel "$2" ; shift 2 ;;
        -b|--blu*)       add_color_to_config blu "$2" ; shift 2 ;;
        -m|--mag*)       add_color_to_config mag "$2" ; shift 2 ;;
        -c|--cya*)       add_color_to_config cya "$2" ; shift 2 ;;
        -w|--whi*)       add_color_to_config whi "$2" ; shift 2 ;;

        -h|--hel*)       usage ; exit 0 ;;

        --)         shift ; break ;;

        *)          echo 'Unknown option!' ; exit 1 ;;
    esac
done

spc -R -c "$CFGFILE" "$@"
rm -f "$CFGFILE"
cas
quelle
1
Übrigens, wenn Sie verwendet haben, können supercatSie das von Ihnen veröffentlichte Skript ändern, um eine temporäre Konfigurationsdatei basierend auf den Befehlszeilenargumenten zu generieren, und dann aufrufen spc -c /path/to/your/temp/config. Auf diese Weise können Sie auf einfache Weise unterschiedliche Farben für unterschiedliche Muster in der Befehlszeile angeben.
Cas
Übrigens habe ich dazu ein einfaches Wrapper-Skript geschrieben. Ich muss jetzt zur Arbeit, aber ich werde es aufräumen, einige Kommentare hinzufügen usw. und es später heute veröffentlichen.
Cas
5

Hier ist ein Allzweck-Skript zum Kolorieren von Regex-Mustern (muss wahrscheinlich überarbeitet werden):

#! /bin/bash

color_to_num () {
  case $1 in
    black)  echo 0;;
    red)    echo 1;;
    green)  echo 2;;
    yellow) echo 3;;
    blue)   echo 4;;
    purple) echo 5;;
    cyan)   echo 6;;
    white)  echo 7;;
    *)      echo 0;;
  esac
}

# default values for foreground and background colors
bg=
fg=
bold="$(tput bold)"
italics=""
boundary=""

while getopts f:b:sli option; do
  case "$option" in
    f) fg="$OPTARG";;
    b) bg="$OPTARG";;
    s) bold="";;
    l) boundary=".*";;
    i) italics="$(tput sitm)";;
  esac
done

shift $(($OPTIND - 1))

pattern="$*"

if [ -n "$fg" ]; then
  fg=$(tput setaf $(color_to_num $fg))
fi
if [ -n "$bg" ]; then
  bg=$(tput setab $(color_to_num $bg))
fi

if [ -z "$fg$bg" ]; then
  fg=$(tput smso)
fi

sed "s/${boundary}${pattern}${boundary}/${bold}${italics}${fg}${bg}&$(tput sgr0)/g"

Nennen Sie es hilite.shund verwenden Sie es folgendermaßen:

$ ./BIN_PROGRAM | hilite.sh -f green PASS | hilite.sh -f red FAIL

$ # Here is an example one liner
$ echo -e "line 1: PASS\nline 2: FAIL" | hilite.sh -f green PASS | hilite.sh -f red FAIL
Trevor Boyd Smith
quelle
Ich habe das gemacht, community wikiweil meine Lösung nicht funktioniert.
Trevor Boyd Smith
Eine einfache Möglichkeit zum Testen besteht darin, ein anderes Skript zu erstellen, das Text mit den Schlüsselwörtern "PASS" und "FAIL" wiedergibt. Das würde dann von diesem Skript aufgerufen werden.
Trevor Boyd Smith
Etwas abseits des Themas, aber ich muss darauf hinweisen, dass das Parsen der Ausgabe von $BINvia evalin die Befehlssubstitution wahrscheinlich fragil, umständlich und geradezu gefährlich ist. STDOUT ist ein Stream und soll im Allgemeinen von Stream-ähnlichen Tools verarbeitet werden. Der Versuch, einen gesamten Stream in einer Variablen zu erfassen, ist nicht sehr effizient. Auch evalist gefährlich mächtig , so dass nur es verwenden , wenn Sie wirklich wissen , was Sie tun.
jw013
Ich habe das Skript durch ein funktionierendes ersetzt.
Angus
@angus, wirklich sehr, sehr gutes und beeindruckendes Skript IMO.
Trevor Boyd Smith
3

Das Einbetten beliebiger Zeichenfolgen (wie der tputAusgabe) in sedErsetzungsausdrücke ist problematisch, da Sie sicherstellen müssen, dass die Zeichenfolge (durch Escapezeichen) eine gültige sedSyntax aufweist. Dies ist komplexer und wird am besten vermieden. Ich würde awkstattdessen verwenden. Nur als Beispiel:

{ echo line 1: PASS; echo line 2: FAIL; } | 
    awk -v "red=$(tput setaf 1)" -v "green=$(tput setaf 2)" \
        -v "reset=$(tput sgr0)" '
    { for (i = 1; i <= NF; i++) {
           if ($i == "FAIL") printf "%s", red "FAIL" reset;
           else if ($i == "PASS") printf "%s", green "PASS" reset;
           else printf "%s", $i

           if (i == NF) printf "%s", ORS
           else printf "%s", OFS 
      }}'

Der Schlüssel besteht darin, die tputSequenzen awkVariablen zuzuweisen , die hier mithilfe der -vOptionen ausgeführt werden.

jw013
quelle
Ich habe Ihr Programm ausgeführt und es macht das, was benötigt wird. Huzzah! Aber leider bin ich kein Awk-Guru, daher fällt es mir schwer zu verstehen, was los ist. Korrigieren Sie mich, wo ich falsch liege. Für jede neue Zeile wird awk ausgeführt? Die for-Schleife im awk-Quellcode lautet: "für alle Token in der Zeile"? dann verarbeitet es jedes Token?
Trevor Boyd Smith
Awk denkt in Feldern und Aufzeichnungen. Standardmäßig sind Datensätze Textzeilen und Felder sind keine Leerzeichen. Ein awkSkript besteht aus einer Reihe von Blöcken (das Material zwischen den Blöcken {}auf der obersten Ebene). Jeder Block ist mit einer Bedingung verknüpft - in meinem obigen Beitrag gibt es keine, da ich bedingungslos auf jede Eingabezeile reagieren möchte. Awk liest Datensätze aus Dateien oder Standardeingaben (in diesem Fall ist es STDIN b / c, es wurden keine Dateinamen angegeben) und vergleicht sie mit jedem Block der Reihe nach, wobei der Block im Datensatz ausgeführt wird, wenn die Bedingung übereinstimmt.
jw013
2

benutze printf:

printf "\e[%sm%s\e[00m\n" <some_number> <text_in_colour>

z.B.

printf "\e[%sm%s\e[00m\n" 32 yodle

Der letzte \nfügt das Zeilenumbruchzeichen hinzu.

um mögliche Werte zu sehen, versuchen Sie etwas wie:

for i in {0..9} {30..38} {90..98} {100..108};
do
    printf "%d:\e[%sm%s\e[00m\n" $i "$i" yodle;
done

Neben Farbe können Sie Modifikatoren wie Fett- oder Unterstreichung oder farbigen Text mit farbigem Hintergrund hinzufügen, indem Sie die Zahlen kombinieren. So erstellen Sie blauen Text mit grauem Hintergrund, der durch die Verwendung unterstrichen und hervorgehoben wird:

printf "\e[%sm%s\e[00m\n" "4;9;34;107" yodle

Prost,

/ B2S

Born2Smile
quelle
2

Wenn Sie gerne ein BASH-Skript installieren möchten ack, verfügt das hhlighterPaket über nützliche Standardfarben und eine einfache Benutzeroberfläche. Https://github.com/paoloantinori/hhighlighter :

Highlight-Beispiel

Sie können es so verwenden, um Zeilen hervorzuheben, die beginnen mit FAIL:

h -i 'FAIL.*'

oder die enthalten FAIL:

h -i '.*FAIL.*'

oder für verschiedene gängige Protokolleinträge:

h -i '.*FAIL.*' '.*PASS.*' '.*WARN.*'

Und natürlich für eine einzelne Farbe (rot) mit einfachem Grep:

$ printf 'Pass: good job\nFail: bad job\n' | grep -Ei --colour=auto '^|fail.*'

Das ^passt zu jeder Zeile, ist aber ein spezieller Matcher und druckt die gesamte Zeile. Der hervorzuhebende Ausdruck wird nach a definiert |. Weitere Ausdrücke können hinzugefügt werden, solange sie durch getrennt sind |.

Andy
quelle