Как эта переменная работает в системном файле systemd?

9

У меня есть довольно простой файл модуля для службы поддержки обнаружения для экземпляра сервера, на котором я работаю в 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. И почему я могу использовать curlies для COREOS_PRIVATE_IPV4переменной (которая экспортируется из /etc/environment, но не для PORT?

Даниэль Бакмастер
источник

Ответы:

9

Это описано в systemd.service (1) . ${PORT}расширяется с помощью systemd. Чтобы передать в $оболочку нужно написать $$так $${PORT}. Важная строка такова:

Чтобы передать буквальный знак доллара, используйте «$$». Переменные, значение которых неизвестно во время раскрытия, рассматриваются как пустые строки.

Уве Гойдер
источник
Спасибо за это! Теперь это имеет смысл, я не заметил, что переменные могут быть заменены systemd иначе, чем во время выполнения самого скрипта ...
Даниэль Бакмастер
1
  1. если содержимое PORT происходит из другой переменной bash, с которой вы будете иметь дело, indirect referenceпопробуйте:

    ${!PORT}
  2. Я полагаю, вы уверены, что ваша оболочка Bash

похлопывание
источник
Спасибо за ответ! 1. PORTпроисходит из строки в скрипте export PORT=$(docker ...); 2. CoreOS поставляется с bash 4.2
Daniel Buckmaster
ты пробовал ${!PORT}в своем сценарии ??
Пэт
Я сделал, и, кажется, дает тот же результат (пустая строка).
Даниэль Бакмастер