grep: color different parts of output

46 Views Asked by At

I'm trying to output some text from grep and highlight in different colors. This is my data:

    - name: the name
      displayName: "[JIRA REF] the name"
      description: JIRA REF
      exemptionCategory: waiver
      expiresOn: 2024-03-02T00:00:00Z
      policyDefinitionReferenceIds:
        - REFid
      scope: null

I need each key (name, displayName etc) in blue and JIRA REF in red

I've managed to isolate it so the key is one color, but when I add in a secondary condition it only matches that eg

grep -A3 -B4 -P 2024-03-02 --color=auto file.txt \
| grep --color=auto -P \
'expiresOn|displayName|name|exemptionCategory|policyDefinitionReferenceIds|scope|description' \ 
-A3 -B4

will output each key in red, but when I add in

grep -A3 -B4 -P 2024-03-02 --color=auto file.txt \
| grep --color=auto -P \
'expiresOn|displayName|name|exemptionCategory|policyDefinitionReferenceIds|scope|description' \ 
-A3 -B4 \
| GREP_COLOR='mt=01;31' grep --color=auto -P '.{0,0}JIRA.{0,4}' \
-A3 -B4

only the JIRA REF is colored

3

There are 3 best solutions below

2
pmf On BEST ANSWER

An unoptimized "least effort" solution

While there are better solutions elsewhere on this page, this post (going with my comment to provide actual code) focuses on your current approach (using multiple greps, sequentially piped into one another) to highlight what went wrong, and how to fix it for a "least effort" solution.

GREP_COLORS='mt=01;35' grep --color=always -A3 -B4 -P '2024-03-02' file.txt |
GREP_COLORS='mt=01;34' grep --color=always -A3 -B4 -P 'expiresOn|displayName|name|exemptionCategory|policyDefinitionReferenceIds|scope|description' |
GREP_COLORS='mt=01;31' grep --color=always -A3 -B4 -P '.{0,0}JIRA.{0,4}'
#         ^        ^^               ^^^^^^
#     spelling    color         coloring mode

Apart from some uniform formatting to improve readability, the following changes were applied:

  • GREP_COLORS is spelled with an S at the end
  • Setting different colors for each line, including 34 for blue, and leaving 31 for red
  • Changing --color=auto to --color=always as with auto, coloring is only enabled for printing, but disabled when piping into another process. (Thus, the last grep doesn't actually need to be modified for this use-case, but I included it anyway for consistency and potentially needed interoperability.)
1
Gilles Quénot On

With grep, this looks convoluted.

What I would do:

#!/bin/bash

blue=$(tput setaf 4)
red=$(tput setaf 1)
reset=$(tput sgr0)

cat<<EOF | sed -e "s/.*/$blue&$reset/g" -e "s/\[JIRA REF\]/$red\[JIRA REF\]$blue/g"
    - name: the name
      displayName: "[JIRA REF] the name"
      description: JIRA REF
      exemptionCategory: waiver
      expiresOn: 2024-03-02T00:00:00Z
      policyDefinitionReferenceIds:
        - REFid
      scope: null
EOF

Feel free to improve to fit exactly your needs. You have more than a starter script :)

enter image description here

6
Stefan Hegny On

I would use something more flexible than grep, e.g. sed:

sed -e 's/displayName: "[[]\([^]]*\)/displayName: "[\x1b[32m\1\x1b[0m/g' -e 's/\([a-zA-Z]*:\)/\x1b[31m\1\x1b[0m/g' file.txt

It makes use of the ANSI color escapes (https://en.wikipedia.org/wiki/ANSI_escape_code) of VT100 compatible terminal like grep also should.