XDG Base Directory shell scripting tutorial

I’ve mentioned the XDG Base Directory specification a few times over the last months, and people have been curious about how to comply with the specification within their own shell-scripts and programs.

The incoming web traffic to my article “Flatpak, Steam Cloud, and XDG Base Directories” reveals that there is interest in a rudimentary tutorial on how-to meet the requirements of the XDG Base Directories Specification from shell scripting. Please read that article first for an introduction to the XDG Base Directory specification, and a concrete example of the kind of problems that can be caused by not following the specification.

According to the XDG Base Directory Specification, applications should store their data in one of three locations according to the type of data. Applications should discover this location by reading environmental variables, or falling back to a predefined set of default paths only if these variables aren’t set in the environment.

The below table shows the XDG Base Directory environmental variables, their default path, and what type of data goes in what directory:

Env. variable Default path Purpose
$XDG_CACHE_HOME $HOME/.cache/ Temporary non-persistent data that can be recreated from local or downloaded data.
$XDG_CONFIG_HOME $HOME/.config/ Application configuration and state.
$XDG_DATA_HOME $HOME/.local/share/ Unique user-created data.

Reading an environmental variable from a shell script is quite easy; the only trouble is ensuring that the default paths are used when the variables are unset.

The below script assigns the default variables to the XDG Base Directory environmental variables only if they they haven’t already been set in the environment

XDG_CACHE_HOME:=$HOME/.cache
XDG_CONFIG_HOME:=$HOME/.config
XDG_DATA_HOME:=$HOME/.local/share

This will let you use the XDG Base Directory variables as pointers to these directories directly in your script. Note that there is no guarantee that the directories exist, so you’ll also have to test that they do exist and you may need to create them before you can store any data in them.

Applications traditionally create their own unique sub-directory underneath the base directories where they keep their own data. You’ll want to store variables for your own sub-directories without modifying the XDG Base Directory environments themselves.

The below script creates three variables for your application’s sub-directories inside the XDG Base Directories without assigning anything to the XDG Base Directory variables themselves:

PROGRAM_NAME="mygreatapp"

CACHE_DIR="${XDG_CACHE_HOME:-$HOME/.cache}/$PROGRAM_NAME"
CONFIG_DIR="${XDG_CONFIG_HOME:-$HOME/.config}/$PROGRAM_NAME"
DATA_DIR="${XDG_DATA_HOME:-$HOME/.local/share}/$PROGRAM_NAME"

mkdir $CACHE_DIR $CONFIG_DIR $DATA_DIR
chown 700 $CACHE_DIR $CONFIG_DIR $DATA_DIR

The two example scripts in this article targets any modern [mostly-]POSIX-compliant shell such as bash, sh, and zsh; but may not work with non-POSIX-compliant shells like tcsh/C shell.


There are several more directories in the XDG Base Directory specification, and you may be able to obtain several more for common directories like Desktop, Documents, and Downloads by sourcing $(XDG_CONFIG_HOME:-$HOME/.config)/user-dirs.dirs. This file is available in almost all graphical desktop environments where the xdg-user-dirs program is used.

Sources