In short -- it's different because systemd does its own string-splitting, unescaping and expansion, and the logic it uses isn't POSIX-compliant.
You can still do what you want, but you'll need more backslashes:
ExecStart=/bin/bash -c '\
while :; do \
port=$(/usr/bin/docker port my-container 5000 | cut -d: -f2); \
/usr/bin/etcdctl set my-container "{\\\"host\\\": \\\"1\\\", \\\"port\\\": $port}" --ttl 60; \
sleep 45; \
done'
Note the use of \\\"
for every literal "
character in the desired output.
By the way -- personally, I advise against trying to generate JSON through string concatenation -- it's prone to injection vulnerabilities (if someone could put content of their choice in the output of the docker port
command, they could potentially insert other key/value pairs into your data by having , "evil": true
be in the port
variable). This class of issues is avoided by using jq
:
ExecStart=/bin/bash -c '\
while :; do \
port=$(/usr/bin/docker port my-container 5000 | cut -d: -f2); \
json=$(jq -nc \
--arg host 1 \
--arg port "$port" \
'{} | .host=$host | .port=($port | tonumber)'); \
/usr/bin/etcdctl set my-container "$json" --ttl 60; \
sleep 45; \
done'
As a happy side effect, the above avoids needing any literal double-quote characters (the only ones used are syntactic to the copy of sh
), so we don't need any backslashes to be passed through from systemd to the shell.
echo
. That is to say, they want to know how to print"a fun thing"
, nota fun thing
. – Mesothelium