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
.