I am running some unit test code. The unit test code outputs regular text. There is a lot of the text so I want to highlight for the user important keywords.
In this case the keywords are “PASS” and “FAIL”.
How do you colorize “PASS” to be green and “FAIL” to be red?
Answers:
Thank you for visiting the Q&A section on Magenaut. Please note that all the answers may not help you solve the issue immediately. So please treat them as advisements. If you found the post helpful (or not), leave a comment & I’ll get back to you as soon as possible.
Method 1
supercat seems to do what you’re looking for.
Package: supercat Description-en: program that colorizes text for terminals and HTML Supercat is a program that colorizes text based on matching regular expressions/strings/characters. Supercat supports html output as well as standard ASCII text. Unlike some text-colorizing programs that exist, Supercat does not require you to have to be a programmer to make colorization rules. Homepage: http://supercat.nosredna.net/
There doesn’t seem to be any way to tell it what to colourise on the command line, you have to specify a config file.
I seem to recall there used to be a program called ‘hilite’ or ‘hl’ that highlighted text that matched a pattern (like grep --colour, but displaying non-matching lines too), but I couldn’t find it when I searched for it.
Finally, GNU grep can be used to highlight patterns – but only one colour can be used (i.e. you can’t have PASS in green and FAIL in red, both would be highlighted with the same colour).
Pipe your data through something like this:
egrep --color "b(PASS|FAIL)b|$"
This example uses egrep (aka grep -E), but -G basic regexp, -F fixed-string, and -P PCRE also work.
All matches will be highlighted. Default is red, or set the GREP_COLOR env var.
The key to this working is that the final |$ in the pattern matches end-of-line (i.e. all lines match) so all lines will be displayed (but not colorised).
The b are word-boundary markers so that it matches e.g. FAIL but not FAILURE. they’re not necessary, so remove them if you want to match partial words.
Here’s the example wrapper script for supercat that I wrote yesterday. It works, but in writing it, I discovered that supercat doesn’t have any option for case-insensitive searches. IMO, that makes the program significantly less useful. It did, however, greatly simplify the script because I didn’t have to write a ‘-i’ option 🙂
#! /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" -- "[email protected]")
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" "[email protected]"
rm -f "$CFGFILE"
Method 2
Here is a general-purpose script to colorize regex patterns (probably needs some retouching):
#! /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"
Name it hilite.sh and use it this way:
$ ./BIN_PROGRAM | hilite.sh -f green PASS | hilite.sh -f red FAIL $ # Here is an example one liner $ echo -e "line 1: PASSnline 2: FAIL" | hilite.sh -f green PASS | hilite.sh -f red FAIL
Method 3
Embedding arbitrary strings (like tput output) into sed replace expressions is problematic because you have to ensure (by escaping) the string is valid sed syntax, which is more complexity that is best avoided. I would use awk instead. Just as an example:
{ 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
}}'
The key is to assign the tput sequences to awk variables, done here using the -v options.
Method 4
use printf:
printf "e[%sm%se[00mn" <some_number> <text_in_colour>
eg.
printf "e[%sm%se[00mn" 32 yodle
the last n adds the newline character.
to see possible values of try something like:
for i in {0..9} {30..38} {90..98} {100..108};
do
printf "%d:e[%sm%se[00mn" $i "$i" yodle;
done
besides colour you can add modifiers like bold or underline or coloured text with coloured background by combining the numbers. To create blue text with grey background that is underlined and striked through use:
printf "e[%sm%se[00mn" "4;9;34;107" yodle
Cheers,
/B2S
Method 5
If you’re happy to install a BASH script and ack, the hhlighter package has useful default colours and an easy interface https://github.com/paoloantinori/hhighlighter:
You can use it like so to highlight rows that start with FAIL:
h -i 'FAIL.*'
or that contain FAIL:
h -i '.*FAIL.*'
or for various common log entries:
h -i '.*FAIL.*' '.*PASS.*' '.*WARN.*'
And of course, for a single colour (red) with plain grep:
$ printf 'Pass: good jobnFail: bad jobn' | grep -Ei --colour=auto '^|fail.*'
The ^ matches every line, but is a special matcher and prints the entire line. The the expression to be highlighted is defined after a |. Further expressions can be added as long as they’re separated with |.
All methods was sourced from stackoverflow.com or stackexchange.com, is licensed under cc by-sa 2.5, cc by-sa 3.0 and cc by-sa 4.0
