14

Is there a command which can be used to easily highlight (with colors, bold text or inverted back-/foreground) specific strings in stdin while passing the entire string to stdout? I'm thinking of building it, but I'd rather just use it if it already exists. Some desirable features:

  1. Separate highlight strings are highlighted differently, in an automatic way. For example, the first string will be highlighted in red, the second in green, the third in blue without manual configuration.
  2. Detects color support and falls back to bold/inverted/other highlighting methods where those are available.
  3. Allow for matching of regular expressions and literal strings.
  4. Preferably does something smart if the matches overlap, such as "foobar" and "barbar".
  5. Nothing is modified between stdin and stdout except for the addition of color codes.
Gilles 'SO- stop being evil'
  • 807,993
  • 194
  • 1,674
  • 2,175
l0b0
  • 50,672
  • 41
  • 197
  • 360
  • 1
    See http://unix.stackexchange.com/questions/8414/ – mattdm Mar 16 '11 at 14:01
  • Ooo, good question. I needed this exact thing and ended up writing something, but it just color-coded fixed strings, it didn't have any of the features you listed – Michael Mrozek Mar 16 '11 at 14:11
  • Rather than writing a new utility, it'd be super-awesome to see this as an addition to grep itself. – mattdm Mar 16 '11 at 14:20
  • 1
    Proper unix philosophy would be a new utility that can be piped through from not only grep but other streams as well. I suspect there's at least one or more Perl modules that can probably do this for you, though... – Shadur Mar 16 '11 at 14:39
  • The problem with piping this is that a lot of stuff will show unexpected output because of the embedded escape codes. It would typically be the last command in the pipeline. – l0b0 Mar 16 '11 at 14:52
  • Well, except grep already does the pattern matching. – mattdm Mar 16 '11 at 15:03
  • @l0b0: Does [this previous question](http://unix.stackexchange.com/questions/8414/) (indicated by mattdm) meet your requirements? If not, what more do you want? (So we know whether to try harder or close your question as a duplicate.) – Gilles 'SO- stop being evil' Mar 16 '11 at 21:53
  • 1
    @Gilles: That question is much more limited in scope. In fact, reading it was one of the reasons I created this question - To ask for a more general and flexible solution. – l0b0 Mar 17 '11 at 08:00
  • When you have a single regexp to highlight, see [Convince grep to output all lines, not just those with matches](http://unix.stackexchange.com/questions/366/convince-grep-to-output-all-lines-not-just-those-with-matches). – Gilles 'SO- stop being evil' Mar 17 '11 at 23:26

7 Answers7

6

Sed to the rescue!

You can improve this (as it really need it) but it works pretty well.

$ cat >~/bin/hilight <<EOF
#!/bin/bash
while [ $# -gt 0 ]
do
 COMANDO=$COMANDO's/'$1$'/\033[01;'$2$'m\033[K\\0\033[m\033[K/g\n'
 shift;shift;
done

sed -e "$COMANDO"
EOF

For sake of simplicity, hilight accepts pair of arguments (first the match, second the color) In this script the attrib is always bold

Read man console_codes (Graphic Rendition) to see color escape secuences, or try this

for attrib in $(seq 0 12); do
  for color in $(seq 30 37) $(seq 40 47) $(seq 90 97); do
    printf %b " $attrib $color:\033[$attrib;${color}mhi, dudes\033[m"
  done
done

It has important drawbacks as using this works:

$ dmesg | hilight \\[ 34 ] 34

but this not at all:

$ dmesg | hilight \\[ 34 ] 34 [[:digit:]] 31

because [:digit:] finds the numbers in the escape secuences on previous sustitutions.

Something like:

$ cat /var/log/kern.log | hilight kernel 31 a 34 et 33

will always work as excepted.

Using time command I found this increments by four the time elapsed, which is not too much.

You can replace sed command with any other parser you like or fits your needs (awk, etc...)

Gilles 'SO- stop being evil'
  • 807,993
  • 194
  • 1,674
  • 2,175
nenopera
  • 61
  • 1
  • 1
4

One can also use egrep with pattern that matches every line on non-printable character, like:

dmesg | egrep --color "swap|$"
4

Maybe Radovan Garabík's Generic Colouriser (grc)? It expects a config file as argument and works with regexp's. So not quite without configuration, but you can use process process substitution (<(list)), so by all means without manual configuration :-)

Gilles 'SO- stop being evil'
  • 807,993
  • 194
  • 1,674
  • 2,175
wnrph
  • 1,414
  • 13
  • 16
  • To clarify without needing to open the page (and to make it searchable), "this one" == *[Generic Colouriser](http://kassiopeia.juls.savba.sk/~garabik/software/grc.html)*; *grc* and *grcat* ... Thanks, I like it. – Peter.O Jul 27 '11 at 11:33
  • `grc` has a helper script: `grcat`. Here is an example of colouring all capital letters in red. Step 1: Set up the config file: `printf "regexp=[A-Z]\ncolours=red\n" > ~/.grc/red-caps` Step 2; Use it: `echo Hello World | grcat red-caps` ... The man page states 3 config directories it searches, and then suggests(?) that the config file can be an absolute path, but this last method of finding the config file only works with relative paths for me (grc version 1.3) – Peter.O Nov 01 '11 at 01:49
2

If your version of grep comes with coloration, then you can use regexp alteration to make grep highlight the text and also match every line so that nothing is excluded. The following should do the trick:

<your command> |grep "highlightme\|^"
EoghanM
  • 887
  • 2
  • 10
  • 15
1

clide works fine. I use it on RHEL 6.2, from the EPEL repository

golimar
  • 387
  • 2
  • 16
0

I use http://em.readthedocs.org/. Easy to install on various platforms because of Python. Simple and works fine.

  • Welcome to Unix & Linux Stack Exchange! Whilst this may theoretically answer the question, [it would be preferable](http://meta.stackexchange.com/q/8259) to include the essential parts of the answer here, and provide the link for reference. – slm Jan 22 '14 at 15:02
  • 2
    According to [help/behavior]: “However, you _must_ disclose your affiliation in your answers.” In case you are the same Igor Kalnitsky who wrote `em`, please reword your answer to be clear that you are not a user, but the author of the suggested tool. – manatwork Jan 22 '14 at 15:18
0

While imperfect and unrefined, for simple highlights in bash strings, the grep command then grep again, ie grep piped to grep, can make quick work of simple highlight with the -B before and/or -A after options. Easier than sed command or others for simple jobs.

man journalctl | grep  EXAMPLE -A100 | grep -A20 highlightword1

grep DOCFOCUSWORDSECTIONETC -B20 -A100  filename.txt  | grep -P highlightword1 -B20 -A20 

Use >> file.txt or >> tee for cleanup edits .

Use smaller or larger, - B Before and/or -A After line number options to narrow or expand ranges of text as required, ie -B1000 -A1000 for a full document. Bonus - overlaps are not repeated. Limits - single color highlight.

Aside, a quick note for grep newbies, try:

grep -i "word1\|word2\|word3" fname.md
grep -Pi "word1|word2|word3" fname.md
grep -Pi "^.*word1|word2.*next|word2.*$"  fname

Use -i for CAPS/not and -P for simple | for OR. Don't confuse the | for OR with | for PIPE to. ^ for line start and $ for line end in -P regex.

Aside, maybe more apt solution to question here is the app batcat (apt install batcat) that has good set of default --language options and new custom syntax/languages can be added.

FargolK
  • 1,629
  • 1
  • 12
  • 20
Cymatical
  • 101
  • 1
  • 4