我有一个相当简单的单元文件,用于在 CoreOS 上运行的服务器实例的发现 Sidekick 服务。该单元文件如下所示:
[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
这工作正常,但我花了很长时间才到达这个阶段,因为如果我将这一行改为etcdctl
这样:
etcdctl set /services/frontend/%i "${COREOS_PRIVATE_IPV4}:${PORT}" --ttl 60; \
然后它就不起作用了——它最终设置了一个像 这样的值100.45.218.3:
,没有端口。在此过程中,我花了很多时间尝试使用$PORT
变量的不同用法,但我不知道为什么我确定的配置有效。有一次我在脚本中写了这个:
echo hi $PORT; \
echo "hi $PORT"; \
echo hi ${PORT}; \
echo "hi ${PORT}"; \
并得到如下日志:
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
本质上,我的问题是:这是怎么回事?这与我理解的 Bash 脚本的工作方式背道而驰{}
。为什么我可以对COREOS_PRIVATE_IPV4
变量使用花括号(从 导出/etc/environment
,但不能用于PORT
?
答案1
这记录在systemd.服务(1).${PORT}
由 systemd 扩展。要将 传递$
给 shell,您需要编写$$
,因此$${PORT}
。重要的一行是:
要传递文字美元符号,请使用“$$”。在扩展时未知值的变量将被视为空字符串。
答案2
如果 PORT 的内容来自其他 bash 变量,则请
indirect reference
尝试:${!PORT}
我假设你确定你的 shell 是 Bash