Come funziona l'escaping variabile in un file di unità systemd?


9

Ho un file di unità abbastanza semplice per un servizio sidekick di rilevamento per un'istanza del server che sto eseguendo su CoreOS. Il file dell'unità è simile al seguente:

[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

Funziona bene, ma mi ci sono voluti anni per arrivare a questo stadio, perché se cambio la etcdctllinea in questo modo:

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

Quindi non funziona: finisce per impostare un valore come 100.45.218.3:, senza porta. Lungo la strada ho trascorso molto tempo a giocare con diversi usi della $PORTvariabile e non ho idea del perché la configurazione su cui mi sono basato funziona. Ad un certo punto ho avuto questo nella sceneggiatura:

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

E ho registri del diario come questo:

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

Essenzialmente la mia domanda è: cosa sta succedendo qui? Questo vola di fronte a come ho capito {}di lavorare negli script bash. E perché posso usare i ricci sulla COREOS_PRIVATE_IPV4variabile (da cui viene esportato /etc/environment, ma non per PORT?

Risposte:


9

Questo è documentato in systemd.service (1) . ${PORT}viene espanso da systemd. Per passare $alla shell è necessario scrivere $$, quindi $${PORT}. La linea importante è questa:

Per passare un segno di dollaro letterale, usa "$$". Le variabili il cui valore non è noto al momento dell'espansione vengono trattate come stringhe vuote.


Grazie per quello! Ciò ha senso ora, non ho notato che le variabili potrebbero essere sostituite da systemd in modo diverso durante l'esecuzione dello script stesso ...
Daniel Buckmaster,

1
  1. se il contenuto di PORT proviene da qualche altra variabile bash di cui ti occuperai, indirect referenceallora prova:

    ${!PORT}
  2. Presumo che tu sia sicuro che la tua shell sia Bash


Grazie per la risposta! 1. PORTproviene da una riga della sceneggiatura export PORT=$(docker ...); 2. CoreOS viene fornito con bash 4.2
Daniel Buckmaster,

hai provato ${!PORT}nella tua sceneggiatura ??
Pat

L'ho fatto e sembra dare lo stesso risultato (una stringa vuota).
Daniel Buckmaster,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.