Comment cette variable d'échappement fonctionne-t-elle dans un fichier d'unité systemd?

9

J'ai un fichier unitaire assez simple pour un service d'accompagnement de découverte pour une instance de serveur que j'exécute sur CoreOS. Le fichier d'unité ressemble à ceci:

[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

Cela fonctionne bien, mais il m'a fallu beaucoup de temps pour arriver à ce stade, car si je change la etcdctlligne en ceci:

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

Ensuite, cela ne fonctionne pas - il finit par définir une valeur comme 100.45.218.3:, sans port. En cours de route, j'ai passé beaucoup de temps à jouer avec différentes utilisations de la $PORTvariable, et je ne sais pas pourquoi la configuration sur laquelle j'ai opté fonctionne. À un moment donné, j'avais ceci dans le script:

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

Et obtenu des journaux de journal comme celui-ci:

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

Essentiellement, ma question est: que se passe-t-il ici? Cela va à l'encontre de ma compréhension {}du travail dans les scripts bash. Et pourquoi puis-je utiliser des curlies sur la COREOS_PRIVATE_IPV4variable (qui est exportée depuis /etc/environment, mais pas pour PORT?

Daniel Buckmaster
la source

Réponses:

9

Ceci est documenté dans systemd.service (1) . ${PORT}est développé par systemd. Pour passer l' $au shell vous devez écrire $$, donc $${PORT}. La ligne importante est la suivante:

Pour passer un signe dollar littéral, utilisez "$$". Les variables dont la valeur n'est pas connue au moment de l'expansion sont traitées comme des chaînes vides.

Uwe Geuder
la source
Merci pour ça! Cela a du sens maintenant, je n'ai pas remarqué que les variables pouvaient être remplacées par systemd différemment de lors de l'exécution du script lui-même ...
Daniel Buckmaster
1
  1. si le contenu de PORT provient d'une autre variable bash avec laquelle vous auriez affaire, indirect referenceveuillez essayer:

    ${!PORT}
  2. Je suppose que vous êtes sûr que votre coquille est Bash

Tapoter
la source
Merci pour la réponse! 1. PORTprovient d'une ligne du script export PORT=$(docker ...); 2. CoreOS est livré avec bash 4.2
Daniel Buckmaster
avez-vous essayé ${!PORT}dans votre script ??
Pat
Je l'ai fait, et cela semble donner le même résultat (une chaîne vide).
Daniel Buckmaster