0

When the text directly contained color code for example:

a="\033[0;31mRED\033[0m"
echo -e $a

The terminal had no problem colorizing the text in red. But when I modified the color code indirectly:

#!/bin/bash

# define color mappings
declare -A colors=(
    ['r']='\033[0;31m'  # Red (escaped for sed/printf)
    ['reset']='\033[0m'  # Reset color
)

# Sample text
t="abc def [ghi] jkl
nmo [ttt] dfd
and more"
# colorize all [...] in red
echo -e "$t" | sed "s/\(\[[^]]*\]\)/\\${colors[r]}\1\\${colors[reset]}/g"

The result was

abc def \033[0;31m[ghi]\033[0m jkl
nmo \033[0;31m[ttt]\033[0m dfd
and more

The terminal did not colorize [...]s with red color at all but showed the raw color codes. It seems like the problem is related to the timing of variable expansion of some sort.

3 Answers 3

3

The problem is not in variable expansion. The problem is you need echo -e to interpret the colour codes, but you run echo -e only for the original string. You then insert the colour codes, but this doesn't go through echo -e anymore. So, one way is to add it:

echo -e $(echo "$t" | sed "s/\(\[[^]]*\]\)/\\${colors[r]}\1\\${colors[reset]}/g" )

You can also store directly the colour codes, not their escaped variant. Then, you can directly output them without needing -e:

declare -A colors=(
    ['r']=$'\033[0;31m'   # <- See the dollar sign?
    ['reset']=$'\033[0m'  # <- It interprets the escape sequences.
)

The rest of the script can stay as it was, but you don't need -e for the output:

echo "$t" | sed "s/\(\[[^]]*\]\)/\\${colors[r]}\1\\${colors[reset]}/g"
Sign up to request clarification or add additional context in comments.

Comments

0

You can call echo -e from within the sed command

$ sed "s/\[[^]]*]/$(echo -e ${colors[r]}\&${colors[reset]})/" <<< "$t"

Or, you could just use tput

sed -E "s/(\[)([^]]*)/\1$(tput setaf 1)\2$(tput sgr 0)/" <<< "$t"

Comments

0

You might find an awk script more flexible than bash+sed, e.g.:

$ cat tst.sh
#!/usr/bin/env bash

t="abc {def} [ghi] 'jkl
nmo' [ttt] dfd
and {more}"

# colorize all [...] in red, '...' in blue, and '{...}' in green

awk '
    BEGIN {
        red    = "\033[1;31m"
        green  = "\033[1;32m"
        blue   = "\033[1;34m"
        reset  = "\033[0m"
    }
    { rec = rec $0 ORS }
    END {
        rec = highlight(rec, "[", "]", red)
        rec = highlight(rec, "\047", "\047", blue)
        rec = highlight(rec, "{", "}", green)
        printf "%s", rec
    }

    function highlight(tail, begChar, endChar, color,           head) {
        head = ""
        while ( match(tail, "[" begChar "][^" endChar "]+[" endChar "]") ) {
            head = head substr(tail,1,RSTART) color substr(tail,RSTART+1,RLENGTH-2) reset
            tail = substr(tail,RSTART+RLENGTH-1)
        }
        return head tail
    }
' <<<"$t"

enter image description here

Note that that's coloring multiple sections of input, including those that include newlines such as 'jkl<newline>nmo'.

See also the following for more examples of coloring with awk:

  1. calendar-highlight-in-unix
  2. Replace html tag data in bash scripting
  3. searching-and-coloring-lines-by-awk-or-other-method
  4. Using awk to color the output in bash
  5. Read file by character to colorify but output by line

and this for shell:

  1. tput-setaf-color-table-how-to-determine-color-codes

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.