У меня есть довольно простой файл модуля для вспомогательной службы обнаружения для экземпляра сервера, на котором я работаю в CoreOS. Юнит-файл выглядит так:
[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
?
Это задокументировано в systemd.service (1). ${PORT}
расширяется systemd. Чтобы пройти $
в оболочку нужно написать $$
, так $${PORT}
. Важная строка такова:
Чтобы передать буквальный знак доллара, используйте «$$». Переменные, значение которых неизвестно во время раскрытия, обрабатываются как пустые строки.
если содержимое PORT поступает из какой-либо другой переменной bash, вы будете иметь дело с indirect reference
тогда попробуйте:
${!PORT}
Я полагаю, вы уверены, что ваша оболочка - это Bash