2

I've looked online for an answer to this but haven't been able to find any answer around this (looking up bash and color yields results for a lot of other color related things).

What I would like to do is implement a --color=(never|always|auto) argument in my own bash scripts similar to the option in ls, grep or other commands. I've never understood how the auto option works under the covers to tell if the output of a command is being piped or redirected.

I'm thinking of an example something like this:

example.sh
#!/bin/bash

text="This is some text"

if [[ "$1" == "--color=always" ]]; then
  echo -e "\e[1;36m${text}\e[0m" # light blue
elif [[  "$1" == "--color=never" ]]; then
  echo "$text"
elif [[  "$1" == "--color=auto" ]]; then
  if [ Being Redirect or Piped ]; then
    echo "$text"
  else
    echo -e "\e[1;36m${text}\e[0m" # light blue
  fi
fi

I've done some testing, if I specify color codes in a string that I echo then when it is piped/redirected the color codes will also get piped/redirected (the behaviour we'd expect with --color=always). Additionally if I don't place color codes in my echoed text this is the behaviour I would expect from --color=never (obviously). What I can not figure out is how to get something like --color=auto to work which is aware of pipes and redirects; something that function like the following:

./example.sh --color=auto
=> This is some text # Entire string is colored light blue
./example.sh --color=auto | grep "text"
=> This is some text  # Piped text isn't colored so only "text" ends up colored  from the grep command (if grep is set to color it)

I'm not sure how to implement this (or if it is even possible) and googling has been unhelpful so far. I'm not sure if this helps or is relevant but I am a linux user (Ubuntu) and use a terminal with xterm-256color, I'm not concerned about portability right now but would be curious for any solutions if there are limitations on the types of terminals it will work on. Any guidance on this would be really appreciated.

2 Answers 2

4

Colors are only meaningful when the data are outputted to terminals so options like --color=auto only need to check whether it's printing to a tty/pty. For Bash you can write like this:

color=... # auto | always | never
...
if [[ $color == auto ]]; then
  # 0 for stdin, 1 for stdout, 2 for stderr
  if [[ -t 1 ]]; then
    # we're writing to a tty so use colors
    ...
  else
    # not a tty, no colors
    ...
  fi
fi

Other languages would usually have a function like C's isatty(3) to check whether an open file is a tty or not.

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

Comments

2

Use function. Use variables. Properly structure code. Your code could look like the following:

# parse arguments
color=... # auto | always | never

color_green() {
     if ((!use_color)); then return; fi
     echo "Output green color code"
}
color_reset() {
     if ((!use_color)); then return; fi
     echo "Output reset color code"
}
printf_green() {
    color_green
    printf "$@"
    color_reset
    printf "\n"
}

use_color=0
# enable coloring when always, or when output is a tty and auto
if [[ "$color" == always || ( "$color" == auto && -t 1 ) ]]; then
  use_color=1
fi

printf_green "Hello world"

if there are limitations on the types of terminals it will work on.

The -t switch is standard and should be available everywhere. It calls isatty() internally. Testing is fd 1 is a terminal, you are basically testing if output is visible for user or if it goes to another program (ie. pipe) instead.

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.