Bash – Why does bash parameter expansion not work inside systemd service files

bashenvironment-variableslinuxsystemd

I am trying to use systemd's EnvironmentFile and add an option to the command when it is set in the file. I have the following in the unit file:

ExecStart=/usr/bin/bash -c "echo ${PORT:+port is $PORT}"

which doesn't echo anything when I start the service.

The following works as expected:

ExecStart=/usr/bin/bash -c "echo port is $PORT"

which means that the file is read correctly.

Parameter substitution also works on command line:

$ PORT=1234 bash -c 'echo ${PORT:+port is $PORT}'
port is 1234

What am I missing?

Best Answer

systemd does its own minimalistic shell-style command line parsing of the contents of ExecStart= and other parameters. This minimalistic parsing supports basic environment variable substitution but apparently not things like ${PORT:+port is $PORT}.

You will want to prevent systemd from doing that and let the invoked shell handle it.

From the documentation:

To pass a literal dollar sign, use "$$".

So try this:

ExecStart=/usr/bin/bash -c "echo $${PORT:+port is $$PORT}"

Or better yet, try this:

ExecStart=/bin/sh -c "echo $${PORT:+port is $$PORT}"

because the type of variable expansion you are doing here is POSIX standard and is not a bash-ism. By using /bin/sh instead of bash you will remove an unnecessary dependancy on bash.

Related Question