If I run this command
/bin/bash -c 'while true;do /usr/bin/etcdctl set my-container "{\"host\": \"1\", \"port\": $(/usr/bin/docker port my-container 5000 | cut -d":" -f2)}" --ttl 60;sleep 45;done'
I get back from etcd what I expect {"host":"1", "port":49155}
But if I put it in a systemd file
ExecStart=/bin/bash -c 'while true;do /usr/bin/etcdctl set my-container "{\"host\": \"1\", \"port\": $(/usr/bin/docker port my-container 5000 | cut -d":" -f2)}" --ttl 60;sleep 45;done'
I get back {host:1, port:49155}
Any idea of why the escaping is different inside of the file? How can I fix it? Thanks!!
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.
systemd-escape '\"a fun thing"\'
output: \x5c\x22a\x20fun\x20thing\x22\x5c
[Service]
ExecStart=/bin/sh -c 'echo "\x5c\x22a\x20fun\x20thing\x22\x5c"'
will print a fun thing
Systemd is doing isn't like bash as you now know, hence the escaping problem. In fact, systemd removes single and double quotes after parsing them. That fact is right out of the documentation (I went thru this too, then read :D).
The solution, call a script that echo back that info you need (with escaped quotes) if your purpose allows that.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With