I am running systemd via user (i.e. enable-linger $USER) and I interact with services via systemctl --user

I noticed a strange issue.

Sourcing Type 1

In order for the above systemd to work for a user, I need to add export XDG_RUNTIME_DIR=/run/user/$(id -u) inside my ~/.bashrc

This works fine.

Sourcing Type 2

When I instead source my bashrc as follows, the systemd does not work:

inside .bashrc:

source /path_to_file/my_file.env

inside my_file.env:

XDG_RUNTIME_DIR=/run/user/$(id -u)

Both Sourcing Type 1 and 2 yield the same result when I do echo $XDG_RUNTIME_DIR so I decided to go with Type 2. However then I noticed that when I do systemctl --user daemon-reload the daemon was not running and I got the following error:

Failed to connect to bus: No such file or directory

When I revert back to Souring Type 1, the error is gone and all works as expected.

My question is: What is happening that I am missing here? My main confusion stems from the fact that the env variables are the same, but the end results are not.

  • .env files are not shell scripts and should not be sourced at all. Quoting rules are different, so the value assigned to a name by a .env parser may be different than what the shell will assign.
    – chepner
    Mar 21 at 20:43

1 Answer 1


You forgot the export in your .env file, so the variable isn't actually an environment variable.

Shell variables are not exported to environment by default. Only assignments to an already exported variable will be re-exported automatically; if XDG_RUNTIME_DIR is a brand new variable, it will become a shell internal variable unless you use the export or declare -x builtins. (Or unless the "allexport" shell option is enabled, but using it in .bashrc has some weird gotchas.)

echo $FOO "sees" the variable because the expansion of $FOO in command-line is done by the shell interpreter itself, not by the command – 'echo' doesn't have to access the environment at all, whereas 'systemctl' does.

Instead of echo, you could use declare -p FOO to have the shell itself tell you the variable's state (including showing the x flag if the variable is exported), or use env or printenv to see what the environment looks like from the point of view of an external process (non-exported shell variables simply won't show up here).

Either way, you should never need to do this for interactive logins. This specific variable is supposed to be put in your environment through PAM (by pam_systemd) as soon as you log in – even before your shell is run.

For scripts that need to access another user's services, systemctl --user -M ${USER}@.host will make systemctl itself find the specified user's runtime directory and the D-Bus socket.


Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.