Colors with unix command "watch"?

Viewed 60494

Some commands that I use display colors, but when I use them with watch the colors disappears:

watch -n 1 node file.js

Is it possible to have the colors back on somehow?

8 Answers

While other answers solve this problem, the easiest way to accomplish this is using the unbuffer tool. To use it simply do:

$ watch --color 'unbuffer <your-program>'

This way you don't have to hunt for control sequence enabling flags of your program. The caveat however is that your version of watch should support the --color flag.

You can install unbuffer on Debian or Ubuntu using sudo apt-get install expect.

Other answers might not work if the command does not have option to force color output. Or you might be lazy like me and do not want to browse manual for each command to find the correct setting. I tried a few different techniques:

The script command

Script command captures output as run by an interactive terminal session. With the combination of --color parameter of watch, it retains colors:

watch --color "script -q -c '<command>' /dev/null"

-q is for quiet, -c is for command and /dev/null is the log file, which is not needed as stdout also shows the output.

Edit: This is the best option so far, I left the earlier solution below for the interested.

Earlier try: Rewrite the terminal window

As suggested by some, a simple while loop with clear and sleep can be used to run the command in terminal without capturing its output. This usually causes flicker, as clear removes all characters and then the command take some time to print the new output line by line.

Fortunately, you can fix this with some clever terminal tricks using tput. Just leave the old output visible while writing the new on top.

Here is the script:

#!/bin/sh
trap "tput cnorm" EXIT  # unhide the cursor when the script exits or is interrupted

# simple interval parameter parsing, can be improved
INTERVAL=2s
case $1 in
  -n|--interval)
    INTERVAL="$2"
    shift; shift
  ;;
esac

clear           # clear the terminal
tput civis      # invisible cursor, prevents cursor flicker

while true; do
  tput cup 0 0  # move cursor to topleft, without clearing the previous output
  sh -c "$*"    # pass all arguments to sh, like the original watch
  tput ed       # clear all to the end of window, if the new output is shorter
  sleep "$INTERVAL"
done

The script fixes color problems, but a different bug remains: If the lines of the command output gets shorter, the rest of the line is not necessarily erased, so the output might not match with reality!

unbuffer is a great way to avoid letting process know if it is writing to TTY, but worth noting that watch does not support 8-bit colors and above yet.

If instead of ls you use something more modern like bat or exa, you should append --theme=ansi (not even --theme=base16 works). git log works out of the box because it always uses 3-bit colors (source).

Example:

watch --color -d -n 0.5 'mycommand file | bat --color=always --theme=ansi'

Could also use -f instead of --color=always.

Another alternative could be Pygments.

Related