TTY detection in bash

It's often nice to have colour output when writing shell scripts. For example:

#!/bin/sh
PATH='/sbin:/bin:/usr/sbin:/usr/bin'

success() {
  # Print green OK after message
  printf "%-35s [\e[32m OK \e[m]\n" "$1"
}

success 'Test example...'

This should give output similar to the following:

$ ./example.sh
Test example...                   [ OK ]

Note: The code above uses ANSI escape codes to change the colour of the output.

Redirected output

This becomes a problem if you try to redirect the output:

$ ./example.sh > script_output

If you do this the script_output file will have the ANSI escape codes in it:

$ xxd -g 1 -c 12 script_output
00000000: 54 65 73 74 20 65 78 61 6d 70 6c 65  Test example
0000000c: 2e 2e 2e 20 20 20 20 20 20 20 20 20  ...
00000018: 20 20 20 20 20 20 20 20 20 20 20 20
00000024: 5b 1b 5b 33 32 6d 20 4f 4b 20 1b 5b  [.[32m OK .[
00000030: 6d 5d 0a                             m].

An easy way around this is to check if the stdout file descriptor is pointing at a tty. The -t option in test lets you do this.

#!/bin/sh
PATH='/sbin:/bin:/usr/sbin:/usr/bin'

success() {
  if test -t 1; then
    # Print green OK after message
    printf "%-35s [\e[32m OK \e[m]\n" "$1"
  else
    # Print to stdout without colour
    printf "%-35s [ OK ]\n" "$1"
  fi
}

success 'Test example...'

Note: The test command uses the isatty system call to achieve this.