Como essa variável de escape funciona em um arquivo de unidade systemd?

9

Eu tenho um arquivo de unidade bastante simples para um serviço auxiliar de descoberta para uma instância do servidor que estou executando no CoreOS. O arquivo da unidade fica assim:

[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

Isso funciona bem, mas levei anos para chegar a esse estágio, porque se eu mudar a etcdctllinha para isso:

etcdctl set /services/frontend/%i "${COREOS_PRIVATE_IPV4}:${PORT}" --ttl 60; \

Então não funciona - acaba definindo um valor como 100.45.218.3:, sem porta. Ao longo do caminho, passei muito tempo jogando com diferentes usos da $PORTvariável, e não tenho idéia do porquê da configuração em que decidi funcionar. Em um ponto, eu tinha isso no script:

echo hi $PORT; \
echo "hi $PORT"; \
echo hi ${PORT}; \
echo "hi ${PORT}"; \

E tem registros de diário como este:

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

Essencialmente, minha pergunta é: o que está acontecendo aqui? Isso muda a cara de como eu entendo {}trabalhar em scripts bash. E por que posso usar curlies na COREOS_PRIVATE_IPV4variável (a qual é exportada /etc/environment, mas não para PORT?

Daniel Buckmaster
fonte

Respostas:

9

Isso está documentado em systemd.service (1) . ${PORT}é expandido pelo systemd. Para passar o $para o shell que você precisa para escrever $$, então $${PORT}. A linha importante é esta:

Para passar um cifrão literal, use "$$". Variáveis ​​cujo valor não é conhecido no momento da expansão são tratadas como cadeias vazias.

Uwe Geuder
fonte
Obrigado por isso! Isso faz sentido agora, eu não percebi que as variáveis ​​poderiam ser substituídas pelo systemd de maneira diferente durante a execução do próprio script ... #
319 Daniel
1
  1. se o conteúdo do PORT vier de alguma outra variável bash com a qual você estaria lidando indirect reference, tente:

    ${!PORT}
  2. Presumo que você tenha certeza de que seu shell é Bash

Pat
fonte
Obrigado pela resposta! 1. PORTvem de uma linha no script export PORT=$(docker ...); 2. CoreOS navios com o bash 4.2
Daniel Buckmaster
você tentou ${!PORT}no seu script ??
Pat
Eu fiz, e parece dar o mesmo resultado (uma string vazia).
precisa saber é o seguinte