Automatically customize your terminal's background color

The problem

In my daily work I usually deal with a large number of terminal windows or tabs; I feel it’s convenient to have a way to distinguish them one from the other at a glance, so I looked for a way to automatically change their background color when terminal starts.
Different terminals (e.g. Terminator vs XFCE4-Terminal vs…) support different color schemes and enable different options, but I finally found a bash-only-based solution, which works fine whatever terminal I use.

The solution

Bash supports changing background color through special output sequences: something like

1
2
3
echo -ne "\e]11;#ff0000\a"
echo -ne "\e]11;#0000bb\a"
echo -ne "\e]11;#000000\a"

can be for instance used to set background color to #ff0000, #0000ff, or #000000.

So, everything I need is a way to

  • choose a (background) color based on TTY id
  • apply the chosen color to background through a command like those above
  • do both thing every time a new bash is launched

The first problem can be solved through tty command, which outputs something like

1
2
$ tty
/dev/pts/3

So I can obtain tty number executing tty | tr -d [a-zA-Z/].
Given this tty number, I can select a color from an array, then use it to change background.

Adding to my path a script named change-background-color and calling it in .bashrc allows background color to be chosen automatically whenever I open an instance of bash.

Full code (with explanatory comments)

Bonus: my final implementation of the background color changing script allows two different usages:

  • you can simply issue change-background-color, cyclically choosing the color from a finite set depending upon the tty number, or
  • you can provide a color symbolic name as parameter, using something like change-background-color red or change-background-color olive.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
// .bashcr
change-background-color

// change-background-color, providing the file to be in the $PATH
#!/bin/bash
# Declares known colors as an associative array
declare -A colorsByName
colorsByName[red]=550000
colorsByName[black]=000000
colorsByName[blue]=000066
colorsByName[gray]=333333
colorsByName[purple]=440044
colorsByName[sugar]=004444
colorsByName[olive]=444400
colorsByName[green]=005500
colorsByName[brick]=773311
colorsByName[azure]=4444ff
colorsByName[orange]=c0470e
colorsByName[lightgray]=666666

# Turns known colors into an index-based array, too
declare -a colorsByIndex
n=0
for key in "${!colorsByName[@]}" ; do
colorsByIndex[$n]=${colorsByName[$key]}
n=$(expr $n + 1)
done

if [ $# -eq 1 ] ; then
# Gets color by name
color=${colorsByName[$1]}
else
theTty=$(tty|tr -d [a-zA-Z/])
# Calculates color index as tty_number % known_colors_count
i=$(expr $(tty | tr -d [a-zA-Z/]) % ${#colorsByName[@]})
# Gets color by index
color=${colorsByIndex[${i}]}
fi

if [ -n "$color" ] ; then
echo -ne "\e]11;#${color}\a"
fi

Now the only question is to choose a set of not eye-offending colors… ;-)

Credits