48

I am looking for a definitive way to build shell scripts that generates colored output.

Unfortunately I am having a hard time finding an appropriate lib or good technique for doing this. I found a lot of helpful but simple examples like this. Also the most comprehensive guide that I found until now is this one.

Before I start writing my own library, I want to check if anyone already wrote it

If your solution does not fit into the observations below thats not a problem. I would like also to read it so it can help me out if decide to write my own solution

My main concerns/observations:

  • Needs to be safe. Want to avoid garbage output as not all terminals or pagers/editors (like less, more, vim, and so on) support colored output or more styled output (bold, blinked, italic, etc)
  • Needs to be easy and readable. Using ANSI escape codes directly is horrible: echo -e '\033[32mthis is ugly and \033[1;32mvery green\033[0m'
  • Needs to give me access to the whole color palette and styles for foreground and background text. Most of the examples I found uses only the basic colors for foreground text only.
  • Its preferable to use only simple commands like bash or simpler shells built in commands and/or common commands that can be found on most operating systems. For instance I can use colorize but I would need ruby (that's somewhat ok) and the colorize gem installed (not ok)
  • Tput seems to be a good option as it can manipulate the shell cursor quite well, but it is somewhat simpler/less flexible

Edit

After some research on terminal control and output formatting, I am writing this gist that tries to accomplish this. So far it is doing quite well

2
  • 1
    echo -e '\033[32mthis is ugly and \033[1;32mvery green\033[0m' is not so horrible, when you use variables like RED=\033[32m or even a color array. Commented May 30, 2013 at 18:28
  • Indeed. I wanted to write a more advanced lib but will probably stick to formatting variables inside strings Commented May 31, 2013 at 1:00

9 Answers 9

103

Here is an modified snippet from my dotfiles that should do what you want

RCol='\e[0m' # Text Reset # Regular Bold Underline High Intensity BoldHigh Intens Background High Intensity Backgrounds Bla='\e[0;30m'; BBla='\e[1;30m'; UBla='\e[4;30m'; IBla='\e[0;90m'; BIBla='\e[1;90m'; On_Bla='\e[40m'; On_IBla='\e[0;100m'; Red='\e[0;31m'; BRed='\e[1;31m'; URed='\e[4;31m'; IRed='\e[0;91m'; BIRed='\e[1;91m'; On_Red='\e[41m'; On_IRed='\e[0;101m'; Gre='\e[0;32m'; BGre='\e[1;32m'; UGre='\e[4;32m'; IGre='\e[0;92m'; BIGre='\e[1;92m'; On_Gre='\e[42m'; On_IGre='\e[0;102m'; Yel='\e[0;33m'; BYel='\e[1;33m'; UYel='\e[4;33m'; IYel='\e[0;93m'; BIYel='\e[1;93m'; On_Yel='\e[43m'; On_IYel='\e[0;103m'; Blu='\e[0;34m'; BBlu='\e[1;34m'; UBlu='\e[4;34m'; IBlu='\e[0;94m'; BIBlu='\e[1;94m'; On_Blu='\e[44m'; On_IBlu='\e[0;104m'; Pur='\e[0;35m'; BPur='\e[1;35m'; UPur='\e[4;35m'; IPur='\e[0;95m'; BIPur='\e[1;95m'; On_Pur='\e[45m'; On_IPur='\e[0;105m'; Cya='\e[0;36m'; BCya='\e[1;36m'; UCya='\e[4;36m'; ICya='\e[0;96m'; BICya='\e[1;96m'; On_Cya='\e[46m'; On_ICya='\e[0;106m'; Whi='\e[0;37m'; BWhi='\e[1;37m'; UWhi='\e[4;37m'; IWhi='\e[0;97m'; BIWhi='\e[1;97m'; On_Whi='\e[47m'; On_IWhi='\e[0;107m'; 

Then you can just echo -e "${Blu}blue ${Red}red ${RCol}etc...."

Sign up to request clarification or add additional context in comments.

10 Comments

Thanks demure. I am writing a gist thats based on your answer (added the link to my post)
I may end up borrowing your style vars and $TC sub var
On a Mac, use \x1B instead of \e.
@MaRco85 echoing '\e[0m' will reset the colors. You could also start a new terminal.
If you use \033 instead of \e you don't have to worry about system support.
|
16
echo -e "\033[33;31m Color Text" - red echo -e "\033[33;32m Color Text" - green echo -e "\033[33;33m Color Text" - yellow echo -e "\033[33;34m Color Text" - blue echo -e "\033[33;35m Color Text" - Magenta echo -e "\033[33;30m Color Text" - Gray echo -e "\033[33;36m Color Text" - Cyan 

http://techietent.blogspot.in/2013/03/how-to-echo-colored-text-in-linux-shell.html

1 Comment

please stop using raw control codes, this is not portable, and instead start using tools to generate them like tput
14

I took demure's list as inspiration and did a little DRYing out of it. (And changed \e to the hexadecimal \x1B, since the former isn't supported in OS X's Terminal.app since Snow Leopard.) Here's what I came up with:

## Colours and font styles ## Syntax: echo -e "${FOREGROUND_COLOUR}${BACKGROUND_COLOUR}${STYLE}Hello world!${RESET_ALL}" # Escape sequence and resets ESC_SEQ="\x1b[" RESET_ALL="${ESC_SEQ}0m" RESET_BOLD="${ESC_SEQ}21m" RESET_UL="${ESC_SEQ}24m" # Foreground colours FG_BLACK="${ESC_SEQ}30;" FG_RED="${ESC_SEQ}31;" FG_GREEN="${ESC_SEQ}32;" FG_YELLOW="${ESC_SEQ}33;" FG_BLUE="${ESC_SEQ}34;" FG_MAGENTA="${ESC_SEQ}35;" FG_CYAN="${ESC_SEQ}36;" FG_WHITE="${ESC_SEQ}37;" FG_BR_BLACK="${ESC_SEQ}90;" FG_BR_RED="${ESC_SEQ}91;" FG_BR_GREEN="${ESC_SEQ}92;" FG_BR_YELLOW="${ESC_SEQ}93;" FG_BR_BLUE="${ESC_SEQ}94;" FG_BR_MAGENTA="${ESC_SEQ}95;" FG_BR_CYAN="${ESC_SEQ}96;" FG_BR_WHITE="${ESC_SEQ}97;" # Background colours (optional) BG_BLACK="40;" BG_RED="41;" BG_GREEN="42;" BG_YELLOW="43;" BG_BLUE="44;" BG_MAGENTA="45;" BG_CYAN="46;" BG_WHITE="47;" # Font styles FS_REG="0m" FS_BOLD="1m" FS_UL="4m" 

The BR_ colours are the "bright" or "high-intensity" colours. Done this way, you can even mix them with other font styles. (e.g. underlined bright white)

If you want to bookmark this, I made a gist for it: https://gist.github.com/ian128K/39a490e5aa8d3bb77a8b

Comments

6

Shameless plug... check Rainbow.sh

Usage

Just import rainbow.sh and start using the available functions in your scripts.

source rainbow.sh vargreen=$(echogreen "Grass is green") varred=$(echored "Roses are red") echo "$vargreen ..Crickets are noisy.. $varred" 

enter image description here

1 Comment

@Hugh Perkins License would be MIT, I'll update the repo later today.
5

tput can handle more than is indicated on the page you link to. All tput does is output the characters you would include in your echo statement, based on what appears in the current terminal's termcap/terminfo database. Some examples:

$ tput setaf 5 | hexdump -C 00000000 1b 5b 33 35 6d |.[35m| $ tput setaf 17 | hexdump -C 00000000 1b 5b 33 38 3b 35 3b 31 37 6d |.[38;5;17m| $ tput reset | hexdump -C 00000000 1b 63 1b 5b 3f 31 30 30 30 6c 1b 5b 3f 32 35 68 |.c.[?1000l.[?25h| 

You would use it the same way you use the variable defined in your gist; in fact, you could use it to create your gist, in a portable fashion:

black=$(tput setaf 0) 

Comments

5

I personally use these in my xcol tool that I developed using Andreas Schamanek code as a reference.

#normal=$(tput sgr0) # normal text normal=$'\e[0m' # (works better sometimes) bold=$(tput bold) # make colors bold/bright red="$bold$(tput setaf 1)" # bright red text green=$(tput setaf 2) # dim green text fawn=$(tput setaf 3); beige="$fawn" # dark yellow text yellow="$bold$fawn" # bright yellow text darkblue=$(tput setaf 4) # dim blue text blue="$bold$darkblue" # bright blue text purple=$(tput setaf 5); magenta="$purple" # magenta text pink="$bold$purple" # bright magenta text darkcyan=$(tput setaf 6) # dim cyan text cyan="$bold$darkcyan" # bright cyan text gray=$(tput setaf 7) # dim white text darkgray="$bold"$(tput setaf 0) # bold black = dark gray text white="$bold$gray" # bright white text 

I use these variables in my scripts like so

echo "${red}hello ${yellow}this is ${green}coloured${normal}" 

Checkout my xcol tool for ideas and examples

https://ownyourbits.com/2017/01/23/colorize-your-stdout-with-xcol/

xcol example

1 Comment

background image distracts to detect colors
2

Just in case someone comes here looking for a shell filter colorizing the output, there's a POSIX shell implementation by Alexey Gladkov lurking as utils/cgrep within libshell (it's designed in a pretty defensive manner) as well as his more involved cfilter written in golang.

Comments

1

You can use colors.sh. First you have to source colors.sh to your script then you can use echo like follow:

source colors.sh # with colors.sh sourced, you can use the constants echo "${RED}This is red text${NC}" # or you can use the functions echo $(gray "[INFO] " && green "This is green test") 

There are two approaches. The first is to use functions and the second is to use constants. You can choose what is best for you.

1 Comment

source colors.sh; echo "${RED}This is red text${NC}" doesn't work for me. Using ècho -e` instead works. ?!?
0

Just a quick add to this using all the awesome answers on this thread but also adding support for the --no-color flag and the NO_COLOR environmental variable.

## Enable our easy to read Colour Flags as long as --no-colors hasn't been passed or the NO_COLOR Env Variable is set. ## NOTE: the NO_COLOR env variable is from: https://no-color.org/ if [[ ! $* == *--no-color* && -z "${NO_COLOR}" ]] then ESeq="\x1b[" # Set up our Colour Holders. ResetColor="$ESeq"'0m' # Text Reset Bold="$ESeq"'1m'; Underline="$ESeq"'4m' # Regular Bold Underline High Intensity Black="$ESeq"'0;30m'; BoldBlack="$ESeq"'1;30m'; UnderlineBlack="$ESeq"'4;30m'; IntenseBlack="$ESeq"'0;90m'; Red="$ESeq"'0;31m'; BoldRed="$ESeq"'1;31m'; UnderlineRed="$ESeq"'4;31m'; IntenseRed="$ESeq"'0;91m'; Green="$ESeq"'0;32m'; BoldGreen="$ESeq"'1;32m'; UnderlineGreen="$ESeq"'4;32m'; IntenseGreen="$ESeq"'0;92m'; Yellow="$ESeq"'0;33m'; BoldYelllow="$ESeq"'1;33m'; UnderlineYellow="$ESeq"'4;33m'; IntenseYellow="$ESeq"'0;93m'; Blue="$ESeq"'0;34m'; BoldBlue="$ESeq"'1;34m'; UnderlineBlue="$ESeq"'4;34m'; IntenseBlue="$ESeq"'0;94m'; Purple="$ESeq"'0;35m'; BoldPurple="$ESeq"'1;35m'; UnderlinePurple="$ESeq"'4;35m'; IntensePurple="$ESeq"'0;95m'; Cyan="$ESeq"'0;36m'; BoldCyan="$ESeq"'1;36m'; UnderlineCyan="$ESeq"'4;36m'; IntenseCyan="$ESeq"'0;96m'; White="$ESeq"'0;37m'; BoldWhite="$ESeq"'1;37m'; UnderlineWhite="$ESeq"'4;37m'; IntenseWhite="$ESeq"'0;97m'; #Bold High Intensity Background High Intensity Backgrounds BoldIntenseBlack="$ESeq"'1;90m'; OnBlack="$ESeq"'40m'; OnIntenseBlack="$ESeq"'0;100m'; BoldIntenseRed="$ESeq"'1;91m'; OnRed="$ESeq"'41m'; OnIntenseRed="$ESeq"'0;101m'; BoldIntenseGreen="$ESeq"'1;92m'; OnGreen="$ESeq"'42m'; OnIntenseGreen="$ESeq"'0;102m'; BoldIntenseYellow="$ESeq"'1;93m'; OnYellow="$ESeq"'43m'; OnIntenseYellow="$ESeq"'0;103m'; BoldIntenseBlue="$ESeq"'1;94m'; OnBlue="$ESeq"'44m'; OnIntenseBlue="$ESeq"'0;104m'; BoldIntensePurple="$ESeq"'1;95m'; OnPurple="$ESeq"'45m'; OnIntensePurple="$ESeq"'0;105m'; BoldIntenseCyan="$ESeq"'1;96m'; OnCyan="$ESeq"'46m'; OnIntenseCyan="$ESeq"'0;106m'; BoldIntenseWhite="$ESeq"'1;97m'; OnWhite="$ESeq"'47m'; OnIntenseWhite="$ESeq"'0;107m'; fi 

You can then use these in an echo as below:

echo -e "${BoldGreen}Grabbing our variables${ResetColor}" echo -e "${BoldGreen}Done${ResetColor} ${Red}Moving on ...${ResetColor}" 

To disable output you can either export NO_COLOR=true to disable colours for the whole session or add the flag to individual script calls ./myscript.sh --no-color

This addition was prompted from https://no-color.org/ and some experience of seeing the colour codes appear in things like logs and file outputs making them hard to read. With these flags wrapped around the colour definitions it is easy to turn off colour output from your scripts when you expect a non-console medium is going to be involved.

I also expanded out the colour names for readability, as hopefully you have a bit of an IDE to help when writing scripts; so length isn't as important as readability. I even kept the American color's 😉

I'm not a Bash/shell expert so please let me know any issues you spot; but I hope this helps some people!

1 Comment

please stop using raw control codes, this is not portable, and instead start using tools to generate them like tput

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.