Home > Blockchain >  How to use ANSI color codes to print colored text to bash terminal from a file?
How to use ANSI color codes to print colored text to bash terminal from a file?

Time:10-18

I have a file (file.txt) like this:

Yes
Yes
No
No

and I want to output this file to a bash terminal with "Yes" as green and "No" as red. I have written the following script:

RED='\033[0;31m'
NC='\033[0m'
GREEN='\033[0;32m'

cat file.txt | sed 's/No/${RED}No${NC}/g' | sed 's/Yes/${GREEN}Yes${NC}/g' > color_file.txt

printf "$(cat color_file.txt)"

The output looks like this:

${GREEN}Yes${NC}
${GREEN}Yes${NC}
${RED}No${NC}
${RED}No${NC}

Instead of being colored.

The coloring works if I have a script like:

RED='\033[0;31m'
printf "${RED}No${NC}"

How would I read a file, color its contents and then print to the terminal?

CodePudding user response:

I happen to have a handy bash function to colorize text without having to remember cryptic ANSI escapes or what values map to what numbers. Using it:

#!/usr/bin/env bash

# Map color names to terminfo setaf/setab codes.
declare -A colors=( [black]=0 [red]=1 [green]=2 [yellow]=3 [blue]=4
                    [magenta]=5 [cyan]=6 [white]=7 )

# colorize colorname text
# Returns text wrapped in ANSI color tags. Unknown color names are mapped to white.
colorize() {
    printf "%s%s%s" "$(tput setaf "${colors[$1]:-7}")" "$2" "$(tput op)"
}

greenyes=$(colorize green Yes)
redno=$(colorize red No)
sed -e "s/Yes/$greenyes/g" -e "s/No/$redno/g" file.txt

will print the colorized file.txt to standard output. You can redirect to a different file, or do both at once by piping it to tee, or whatever else you want.

CodePudding user response:

How would I read a file, color its contents and then print to the terminal?

You could leave the expansions in the file and replace the ${...} forms with the variables when reading the file:

RED=$'\E[0;31m'
NC=$'\E[0m'
GREEN=$'\E[0;32m'
sed 's/No/${RED}No${NC}/g ; s/Yes/${GREEN}Yes${NC}/g' file.txt > color_file.txt
( export RED NC GREEN ; envsubst color_file.txt )

But I believe you wanted to actually output the escape sequences into the file:

RED=$'\E[0;31m'
NC=$'\E[0m'
GREEN=$'\E[0;32m'
sed "s/No/${RED}No${NC}/g ; s/Yes/${GREEN}Yes${NC}/g" file.txt > color_file.txt
cat color_file.txt

Or maybe you wanted printf to interpret the escpe sequences in the content of a file:

RED='\033[0;31m'
NC='\033[0m'
GREEN='\033[0;32m'
sed "s/No/${RED}No${NC}/g ; s/Yes/${GREEN}Yes${NC}/g" file.txt > color_file.txt
printf "%b\n" "$(cat color_file.txt)"
# or maybe:
xargs -0 printf "%b" < color_file.txt
# or maybe:
sed 's/\\033/\e/g' color_file.txt 
# etc.

Check your scripts with shellcheck - it will tell you about all mistakes that you did.

's/No/${RED}...'

Variable expansion does not expand within single quotes.

#If you would:
RED='\033[0;31m'
.... sed "....${RED}..."

sed does not interpret octal escape sequences. For sed the string \033 is a zero byte 0x00 followed by two 33.

printf "$(cat ...)"

Is an antipattern. Just execute cat ....

cat ... | sed..

Is a useless use of cat.

how to make printf read the content of the file

It is not possible to read a file with printf. It's not a tool for that.

and therefore execute the commands within it.

This feels unrelated to your issue, but to execute a file just call it with an interpreter sh ./file.sh or source it within current execution environment . ./file.sh.

  • Related