Skip to content
Advertisement

Bash Brace Expansion in Systemd ExecStart

The following test is in CentOS 7.1.

Create the following file test.service in /usr/lib/systemd/system/

[Unit]
Description=Test Bash Brace Expansion
Wants=network.target
After=network.target

[Service]
Type=oneshot
RemainAfterExit=yes
ExecStart=/bin/bash -c "a='hello world'; echo ${a}"

[Install]
WantedBy=multi-user.target

and execute systemctl daemon-reload; systemctl restart test; systemctl status test -l

There is no output of the value as the ${a} does not substitute as the word hello world, until it is changed echo ${a} into

  1. echo $a : Work
  2. echo $${a}: Work

The $$ means a pid of the process in a a bash, but why could the $$ do the trick in ExecStart to probably get the word hello world?

Advertisement

Answer

Brace vs. Parameter expansion

What you are doing is not brace expansion, but parameter expansion. Brace expansion (e.g. ${1..5} does not work inside double quotes.

Your Problem explained with two Bash shells

Parameter expansion does work inside double quotes, but if the substitution should take place in the called shell instead of the current one, the $sign needs to be quoted.

Consider this example:

a='bye world' ; /bin/bash -c "a='hello world'; echo ${a}"
bye world

vs. this one:

a='bye world' ; /bin/bash -c "a='hello world'; echo ${a}"
hello world

Applying the solution to systemd service files and why `$$` works

It is important to remember that your systemd service description file is not executed in Bash (as above examples are), so there are some very similar, but subtly different rules, see the documentation for service unit configuration files.

Your problem is, that like the interactive Bash in the first example above, systemd is trying to expand ${a} which it does not have in its environment. As you have noticed already, $$ is your solution, and above link explains why:

To pass a literal dollar sign, use “$$”.

This allows the parameter expansion to happen in the Bash shell systemd is calling. So the line in the config file should read:

ExecStart=/bin/bash -c "a='hello world'; echo $${a}"
User contributions licensed under: CC BY-SA
7 People found this is helpful
Advertisement