How does this variable escaping work in a systemd unit file?
Solution 1
This is documented in systemd.service(1). ${PORT}
is expanded by systemd. To pass the $
to the shell you need to write $$
, so $${PORT}
. The important line is this:
To pass a literal dollar sign, use "$$". Variables whose value is not known at expansion time are treated as empty strings.
Solution 2
-
if the content of PORT comes from some other bash variable you would be dealing with an
indirect reference
then please try:${!PORT}
I assume you are sure your shell is Bash
Related videos on Youtube
Daniel Buckmaster
Startup founder, renewables advocate, reluctant technophile.
Updated on September 18, 2022Comments
-
Daniel Buckmaster over 1 year
I have a fairly simple unit file for a discovery sidekick service for a server instance I'm running on CoreOS. The unit file looks like this:
[Unit] Description=Discovery for frontend server (instance %i) BindsTo=frontend@%i.service After=frontend@%i.service [Service] EnvironmentFile=/etc/environment ExecStart=/usr/bin/bash -c ' \ while true; do \ export PORT=$(docker port frontend%i 80 | sed s/.*://); \ etcdctl set /services/frontend/%i "${COREOS_PRIVATE_IPV4}:$PORT" --ttl 60; \ sleep 45; \ done' ExecStop=/usr/bin/etcdctl rm /services/frontend/%i [X-Fleet] MachineOf=frontend@%i.service
This works fine, but it took me ages to get to this stage, because if I change the
etcdctl
line to this:etcdctl set /services/frontend/%i "${COREOS_PRIVATE_IPV4}:${PORT}" --ttl 60; \
Then it doesn't work - it ends up setting a value like
100.45.218.3:
, with no port. Along the way I spent a lot of time playing with different uses of the$PORT
variable, and I have no idea why the configuration I settled on works. At one point I had this in the script:echo hi $PORT; \ echo "hi $PORT"; \ echo hi ${PORT}; \ echo "hi ${PORT}"; \
And got journal logs like this:
Aug 17 01:05:07 core-01 bash[53694]: hi 32769 Aug 17 01:05:07 core-01 bash[53694]: hi 32769 Aug 17 01:05:07 core-01 bash[53694]: hi Aug 17 01:05:07 core-01 bash[53694]: hi
Essentially my question is: what's going on here? This flies in the face of how I understand
{}
to work in bash scripts. And why can I use curlies on theCOREOS_PRIVATE_IPV4
variable (which is exported from/etc/environment
, but not forPORT
? -
Daniel Buckmaster over 8 yearsThanks for the response! 1.
PORT
comes from a line in the scriptexport PORT=$(docker ...);
2. CoreOS ships with bash 4.2 -
Pat over 8 yearsdid you try
${!PORT}
in your script?? -
Daniel Buckmaster over 8 yearsI did, and it seems to give the same result (an empty string).
-
Daniel Buckmaster over 8 yearsThanks for that! That makes sense now, I didn't notice that variables could be substituted by systemd differently to during execution of the script itself...