这个变量转义在 systemd 单元文件中如何工作?

这个变量转义在 systemd 单元文件中如何工作?

我有一个相当简单的单元文件,用于在 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

  1. 如果 PORT 的内容来自其他 bash 变量,则请indirect reference尝试:

    ${!PORT}
    
  2. 我假设你确定你的 shell 是 Bash

相关内容