$XDG_CONFIG_HOME:=$HOME/.configđź…­

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’s 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 four 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 which directory. Your users will appreciate you for putting data in the right directories.

Env. variable Default path Purpose
$XDG_CACHE_HOME $HOME/.cache/ Temporary non-persistent data that might be needed later. Cache data can be recreated from other local or downloaded data.
$XDG_CONFIG_HOME $HOME/.config/ Program runtime configuration data.
$XDG_DATA_HOME $HOME/.local/share/ Unique program-specific user-created data.
$XDG_STATE_HOME $HOME/.local/state/ Program state, logs, history, current cursor/reading position, etc.

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 XDG Base Directory specifications defaults should be used in this situation.

The below script assigns the default variables to the XDG Base Directory environmental variables only if they haven’t already been set in the environment. To override these system-wide, you can prefix these commands with the export command and put them in your shell profile.

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

This will let you use the XDG Base Directory variables as pointers to these directories directly in your script. Note that there’s 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 sub-directories without modifying the XDG Base Directory environments themselves.

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

PROGRAM_NAME="my-app"

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"
STATE_DIR="${XDG_STATE_HOME:-$HOME/.local/state}/$PROGRAM_NAME"

mkdir $CACHE_DIR $CONFIG_DIR $DATA_DIR $STATE_DIR
chmod 700 $CACHE_DIR $CONFIG_DIR $DATA_DIR $STATE_DIR

The two example scripts in this article targets any modern POSIX-compatible shell such as bash, sh, and zsh. They may not work with non-POSIX-compatible shells like tcsh/C shell.

There are 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.

Update (): Added the new XDG_STATE_HOME directory as introduced in the XDG Base Directory Specification version 0.8.