The 'dircolors' Command

Introduction

The dircolors command is used to set the colours various filetypes are shown in by the ls command. It also affects at least one other command line utility tree, so there may be other less known utilities affected by this. The changes I'm suggesting here have been unevenly tested across Fedora, Debian, and macOS (two solutions are shown for macOS toward the end of this entry). You'll also need to use ls --color, but at this point most distros automatically alias ls to do this for you. While not directly related to this, I recommend also adding (again, usually aliased by most distros) --classify to help with readability of links, directories, and executables.

Note

I'm Canadian: as far as I'm concerned, the word is spelled "colour." When I reference the utility dircolors or the environment variable(s) $LS_COLORS I'll spell them as you'll need to spell them at the command line. But if I'm referencing the word, it's "colour."

I came to this because on both Linux and Mac the default colour for a directory is a dark blue - on a black background in a terminal, this is sometimes unreadable.

I think it's worth pointing out that while very few people and even less versions of Linux still use 16-colour terminals, they do still exist. I think Debian still configures xterm to be only 16-colours (I'm not sure because I long ago reconfigured it to 256 colours). A lot of the settings below assume your terminals support 256 colours: you should be aware that some terminals and the Linux console don't support this in case you find yourself with things not working as described.

Another assumption that may not suit you is that the terminal background is black. This is true on every machine I run - but I know some people use white backgrounds or other colours. The settings I demonstrate here will need some adjustment in those contexts.

Digging In

ls decides what colours to apply to different filetypes based on the $LS_COLORS environment variable. On Raspberry Pi OS (which is approximately Debian 11) this looks like this:

$ echo $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:*.webp=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:

You could edit this directly. But there's an easier way, which is where the dircolors command comes into this. To get started, take a look at the output of dircolors --print-database to see the default set of values - this includes comments, and they're worth reading. To start modifying this "database," run dircolors --print-database > ~/.dircolors (confirm that file doesn't already exist first). Edit the file (we'll discuss that shortly), then load it back into the current terminal with eval $(dircolors -b ${HOME}/.dircolors). (eval is much maligned - but in this case, dircolors is producing an environment variable we need to bring into the current environment.) Open ~/.dircolors with your preferred editor - although I highly recommend (Neo)Vim for this as it has a :set ft=dircolors syntax-highlighting mode that shows any colour codes as the colour they'll appear in the terminal.

As a starting example (as seen in NeoVim with syntax highlighting on):

LINK 44;01;36
ORPHAN 40;31;01
MISSING 01;37;41

(This isn't the default set of colours, and doesn't exactly match what I see in the terminal because of the HTML conversion, but it's close.) LINK tells it how to highlight links, reasonably enough. ORPHAN matches "symlink to nonexistent file, or non-stat'able file," while MISSING is how to highlight the files that orphans point to. Links are bright cyan, an orphan/broken link is bright red, and (if you do ls -l) the missing file it points to is bright white on a red background. I find broken links being a different colour incredibly useful: it's saved my ass multiple times.

Highlighting is also done by file extension. We'll get to that, and you'll see it a lot in ~/.dircolors.

Colours and Characteristics

Basic colours can be seen in Bash Prompt #1: Colours, to use 256 colours (rather than just 16), see 256 Command Line Colours for the Bash Prompt (#7) and 'ls'/'dircolors'. Here are the colours and characteristics:

  • 30-37 for red, green, yellow, blue, magenta, cyan, grey in that order
  • 40-47 for the same background colours
  • 01;<colour> for bold
  • 03; for italics (not sure it works in all terms, but does work in urxvt and xterm)
  • 04; for underline
  • 05; for blink (inconsistent: doesn't work in urxvt, does work in xterm)
  • there are a lot of other properties ... but they're unsupported or otherwise problematic (see the Bibliography if you're interested in more details)

In ~/.dircolors, 256-colour codes are used like this:

  • 38;5;<256-colour-code> for FG
  • 48;5;<256-colour-code> for BG

For example, to use the orange mentioned in the other blog entry on a dark gray background for all text files (again seen in NeoVim):

# Text
.txt 38;5;208;48;5;236
.text 04;38;5;208;48;5;236

I changed the second one to be underlined as well: this could be useful if you wanted .text files to stand out so you could change them to be just .txt for consistency.

Changing ls Colours on Mac

This is for the default Mac setup. If you want to actually use dircolors it's possible but well off the beaten path: Changing ls Colours on Mac to use 'dircolors'.

On Mac, you need to set the $LSCOLORS environment variable by hand (notice no underscore as $LS_COLORS for dircolors above, and no dircolors command available) - but the setting is very different, much more limited, and despite that reduced complexity, even less intuitive. The default (per the Mac ls man page) looks like this:

LSCOLORS=exfxcxdxbxegedabagacad

The change I needed to make, to make my directories more readable:

LSCOLORS=Defxcxdxbxegedabagacad

export this variable in your ~/.profile to make changes from the default. Each pair of letters represents the foreground and background colours for a particular set of files, and the first pair is directories. There are 11 pairs, detailed below. I went from ex which is "blue-on-default" to De which is "yellow-on-blue."

The colours, from the man page:

a     black
b     red
c     green
d     brown
e     blue
f     magenta
g     cyan
h     light grey
A     bold black, usually shows up as dark grey
B     bold red
C     bold green
D     bold brown, usually shows up as yellow
E     bold blue
F     bold magenta
G     bold cyan
H     bold light grey; looks like bright white
x     default foreground or background

Likewise from the man page, the order of attributes:

1.   directory
2.   symbolic link
3.   socket
4.   pipe
5.   executable
6.   block special
7.   character special
8.   executable with setuid bit set
9.   executable with setgid bit set
10.  directory writable to others, with sticky bit
11.  directory writable to others, without sticky bit

Changing ls Colours on Mac to use 'dircolors'

I don't recommend this, but not only can it be done, I'm using this setup on my Mac. But I consider it fragile and poorly tested (I only made the change a couple days ago). Step one: brew install coreutils. Then add something like the following to your ~/.profile:

if [ -d /usr/local/opt/coreutils/libexec/gnubin/ ]
then
    # GNU 'ls' is available, let's use it
    alias ls="/usr/local/opt/coreutils/libexec/gnubin/ls"
    if [ -e "${HOME}/.dircolors" ]
    then
        eval $(/usr/local/opt/coreutils/libexec/gnubin/dircolors -b "${HOME}/.dircolors")
    else
        eval $(/usr/local/opt/coreutils/libexec/gnubin/dircolors -b)
    fi
    d  () { /usr/local/opt/coreutils/libexec/gnubin/ls --color=tty --classify "$@"; }
    da () { /usr/local/opt/coreutils/libexec/gnubin/ls --color=tty --classify -A "$@"; }
    v  () { /usr/local/opt/coreutils/libexec/gnubin/ls --color=tty --classify -l "$@"; }
    va () { /usr/local/opt/coreutils/libexec/gnubin/ls --color=tty --classify -lA "$@"; }
else
    # with Mac 'ls', "--color=tty" becomes "-G" and "--classify" becomes "-F"
    d  () { ls -G -F "$@"; }
    da () { ls -G -F -A "$@"; }
    v  () { ls -G -F -l "$@"; }
    va () { ls -G -F -lA "$@"; }
fi

IMPORTANT: again, this is NOT well tested, and it's primarily set up to provide my preferred aliases (or functions in this case): d, da, v, and va. You'll need to adapt it to your own use. One of the nastiest problems from my point of view is that this leaves you with a functioning GNU ls (by using an alias to overwrite an existing binary, something I usually recommend against) and if you type man ls you get the Apple/BSD man page which describes a very different version of ls. This can be fixed by modifying $MANPATH, but this leads you further down the rabbit hole ... Your call.