# Tweaking terminal colors with LS_COLORS and dircolors
by Seth Kenlon

You can add color to your Linux terminal using special ANSI encoding settings, either dynamically in a terminal command or in configuration files, or you can use ready-made themes in your terminal emulator.
Either way, the nostalgic green or amber text on a black screen is wholly optional.
This article demonstrates how you can make Linux as colourful (or as monochromatic) as you want.

## Terminal capabilities

It's common on modern systems to default to at least ``xterm-256color``, but if you try to add color to your terminal without success then you should check your ``TERM`` setting.

Historically, UNIX terminals were literally that: physical points at the literal end (termination) point of a shared computer system where users could type in commands.
They were unique from the teletype machines (which is why we still have /dev/tty devices in Linux today) that were often used to issue commands remotely.
Terminals had CRT monitors built-in, so a user could sit at a terminal in their office to interact directly with the mainframe.
CRT monitors were expensive, though, both to manufacture and to control; it was easier to have a computer spit out crude ASCII text than to worry about anti-aliasing and other niceties that modern computerists take for granted.
However, developments in technology happened fast even then, and it quickly became apparent that as new video display terminals were designed, new capabilities needed to be available on an optional basis.

For instance, the fancy new VT100 released in 1978 supported ANSI colour, so if a user identified their terminal type as ``vt100``, then a computer was able to deliver colour output, while a basic serial device might have no such option.
The same principle applies today, and it's set by the TERM [environment variable](https://opensource.com/article/19/8/what-are-environment-variables).
You can check your current TERM definition with ``echo``:

```
$ echo $TERM
xterm-256color
```

The obsolete (but still maintained on some systems in the interest of backward compatibility) ``/etc/termcap`` file defined the capabilities of terminals and printers.
The modern version of that is ``terminfo``, located in either ``/etc`` or ``/usr/share``, depending on your distribution.
These files list features available in different kinds of terminals, many of which are defined by actual historic hardware: there are definitions for ``vt100`` through ``vt220``, as well as definitions for modern software emulators like ``xterm`` and ``xfce``.
Most software doesn't care what terminal type you're using, but in some rare instances you might get a warning or error about an incorrect terminal type when logging into a server that actually checks for compatible features.
If your terminal is set to a profile with very few features but you know the emulator you use is capable of more, then you can change your setting by defining the ``TERM`` environment variable.
You can do this by exporting the ``TERM`` variable in your ``~/.bashrc`` configuration file:

```
export TERM=xterm-256color
```

Save the file, and then reload your settings:

```
$ source ~/.bashrc
```


## ANSI color codes

Modern terminals have inherited ANSI escape sequences for "meta" features.
These are special sequences of characters that get interpreted by a terminal as actions instead of characters.
For instance, there's an sequence to clear the screen up to the next prompt:

```
$ printf `\033[2J`
```

That doesn't clear your history, it just clears the screen up in your terminal emulator, so it's a safe and demonstrative ANSI escape sequence.

ANSI also has sequences to set the color of you terminal.
For example, typing this code changes all following text to green:

```
$ printf '\033[32m'
```

As long as you see color the same way your computer does, then you could use color as a gentle reminder of what system you're logged in to.
For example, maybe you regularly SSH into your server, so you set your server prompt to green to help you differentiate it from your local prompt at a glance.
For a green prompt, use the ANSI code for green before your prompt character and then end it with the code representing whatever is set as your normal default color:

```
export PS1=`printf "\033[32m$ \033[39m"`
```

## Foreground and background

You're not just limited to the color of your text.
With ANSI codes, you can control the background color of your text as well as some rudimentary styling.

For instance, you can cause text to be underlined with \033[4m, or to blink with \033[5m.
That might seem silly at first, because you're probably not going to set your terminal to underline all text whilst blinking all day, but for select functions it can be useful.
For instance, you might set a specific urgent error produced by a shell script to blink as an alert for your user, or you might underline an URL.

For your reference, here are the foreground and background color codes.
Foreground colors are in the 30 range, while background colors are in the 40 range (so 32 sets the foreground text to green, while 42 sets the background to green, and so on).

* \033[30m black
* \033[31m red
* \033[32m green
* \033[33m orange
* \033[34m blue
* \033[35m magenta
* \033[36m cyan
* \033[37m light gray
* \033[39m fallback to the default set by your distribution

There are some additional colors available for the background:

* \033[100m dark gray
* \033[101m light red
* \033[102m light green
* \033[103m yellow
* \033[104m light blue
* \033[105m light purple
* \033[106m teal
* \033[107m white


## Permanency

Setting colors in your terminal session is only temporary, and relatively unconditional.
Sometimes the effect lasts for a few lines, and that's because this method of setting colors relies on a ``printf`` statement to set a mode that lasts only until something else overrides it.

The way a terminal emulator typically gets instructions on what colors to use is from the settings of the LS_COLORS environment variable, which is in turn populated by the settings of ``dircolors``.
You can view your current settings with an echo statement:

```
$ echo $LS_COLORS
rs=0:di=38;5;33:ln=38;5;51:mh=00:pi=40;38;5;11:so=38;5;13:do=38;5;5:bd=48;5;232;38;5;11:cd=48;5;232;38;5;3:or=48;5;232;38;5;9:mi=01;05;37;41:su=48;5;196;38;5;15:sg=48;5;11;38;5;16:ca=48;5;196;38;5;226:tw=48;5;10;38;5;16:ow=48;5;10;38;5;21:st=48;5;21;38;5;15:ex=38;5;40:*.tar=38;5;9:*.tgz=38;5;9:*.arc=38;5;9:*.arj=38;5;9:*.taz=38;5;9:*.lha=38;5;9:
[...]
```

Or you can use dircolors directly:

```
$ dircolors --print-database
[...]
# image formats
jpg 01;35
jpeg 01;35
mjpg 01;35
mjpeg 01;35
gif 01;35
bmp 01;35
pbm 01;35
tif 01;35
tiff 01;35
[...]
```

If that looks cryptic, it's because it is.
The first digit after a file type is the attribute code and has six options:

* 00 none
* 01 bold
* 04 underscore
* 05 blink
* 07 reverse
* 08 concealed

The next digit is the color code in a simplified form.
You can get the color code by taking the final digit of the ANSII code (32 for green foreground, 42 for green background, 31 or 41 for red, and so on).

Your distribution probably sets LS_COLORS globally so that all users on your system inherit the same colors.
If you want a customized set of colours, you can use dircolors for that.
First, generate a local copy of colour settings:

```
$ dircolors --print-database > ~/.dircolors
```

Edit your local list as desired.
When you're happy with your choices, save the file.
Your color settings is just a database and can't be used directly by [ls](https://opensource.com/article/19/7/master-ls-command), but you can use ``dircolors`` to get shell code you can use to set ``LS_COLORS``:

```
$ dircolors --bourne-shell ~/.dircolors
LS_COLORS='rs=0:di=01;34:ln=01;36:mh=00:pi=40;33:so=01;35:do=01;35:bd=40;33;01:cd=40;33;01:or=40;31;01:mi=00:su=37;41:sg=30;43:ca=30;41:tw=30;42:ow=34;42:st=37;44:ex=01;32:*.tar=01;31:*.tgz=01;31:*.arc=01;31:*.arj=01;31:*.taz=01;31:*.lha=01;31:*.lz4=01;31:*.lzh=01;31:*.lzma=01;31:*.tlz=01;31:*.txz=01;31:*.tzo=01;31:*.t7z=01;31:*.zip=01;31:*.z=01;31:*.dz=01;31:*.gz=01;31:*.lrz=01;31:*.lz=01;31:*.lzo=01;31:*.xz=01;31:*.zst=01;31:*.tzst=01;31:*.bz2=01;31:*.bz=01;31:*.tbz=01;31:*.tbz2=01;31:*.tz=01;31:*.deb=01;31:*.rpm=01;31:*.jar=01;31:*.war=01;31:*.ear=01;31:*.sar=01;31:*.rar=01;31:*.alz=01;31:*.ace=01;31:*.zoo=01;31:*.cpio=01;31:*.7z=01;31:*.rz=01;31:*.cab=01;31:*.wim=01;31:*.swm=01;31:*.dwm=01;31:*.esd=01;31:*.jpg=01;35:*.jpeg=01;35:*.mjpg=01;35:*.mjpeg=01;35:*.gif=01;35:*.bmp=01;35:*.pbm=01;35:*.pgm=01;35:*.ppm=01;35:*.tga=01;35:*.xbm=01;35:*.xpm=01;35:*.tif=01;35:*.tiff=01;35:*.png=01;35:*.svg=01;35:*.svgz=01;35:*.mng=01;35:*.pcx=01;35:*.mov=01;35:*.mpg=01;35:*.mpeg=01;35:*.m2v=01;35:*.mkv=01;35:*.webm=01;
35:*.ogm=01;35:*.mp4=01;35:*.m4v=01;35:*.mp4v=01;35:*.vob=01;35:*.qt=01;35:*.nuv=01;35:*.wmv=01;35:*.asf=01;35:*.rm=01;35:*.rmvb=01;35:*.flc=01;35:*.avi=01;35:*.fli=01;35:*.flv=01;35:*.gl=01;35:*.dl=01;35:*.xcf=01;35:*.xwd=01;35:*.yuv=01;35:*.cgm=01;35:*.emf=01;35:*.ogv=01;35:*.ogx=01;35:*.aac=00;36:*.au=00;36:*.flac=00;36:*.m4a=00;36:*.mid=00;36:*.midi=00;36:*.mka=00;36:*.mp3=00;36:*.mpc=00;36:*.ogg=00;36:*.ra=00;36:*.wav=00;36:*.oga=00;36:*.opus=00;36:*.spx=00;36:*.xspf=00;36:';
export LS_COLORS
```

Copy and paste that output into your ``~/.bashrc`` file and then reload.
Alternatively, you can dump that output straight into your ``.bashrc`` file and then reload.

```
$ dircolors --bourne-shell ~/.dircolors >> ~/.bashrc
$ source ~/.bashrc
```

You can also make Bash resolve ``.dircolors`` upon launch instead of doing the conversion manually.
Realistically, you're probably not going to change colors often, so this is probably overly aggressive, but it's an option should you plan on changing your color scheme often.
In your ``.bashrc`` file, add this rule:

```
[[ -e $HOME/.dircolors ]] && eval "`dircolors --sh $HOME/.dircolors`"
```

Should you have a ``.dircolors`` file in your home directory, Bash evaluates it upon launch, and sets LS_COLORS accordingly.

## Color

Colors in your terminal are an easy way to provide yourself with a quick visual reference for specific information.
However, you might not want to lean on them too heavily.
After all, colors aren't universal, so if someone else uses your system, they may not see the colors the same way you do.
Furthermore, if you use a variety of tools to interact with computers, you might also find that some terminals or remote connections don't provide the colors you expect (or colors at all).

Those warnings aside, colors can be useful and fun in some workflows, so create a ``.dircolor`` database and customize it to your heart's content.