Bagaimana variabel ini lolos bekerja dalam file unit systemd?

9

Saya memiliki file unit yang cukup sederhana untuk layanan sidekick penemuan untuk contoh server yang saya jalankan di CoreOS. File unit terlihat seperti ini:

[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

Ini berfungsi dengan baik, tetapi butuh waktu lama bagi saya untuk sampai ke tahap ini, karena jika saya mengubah etcdctlbaris ini:

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

Maka itu tidak berhasil - akhirnya pengaturan nilai seperti 100.45.218.3:, tanpa port. Sepanjang jalan saya menghabiskan banyak waktu bermain dengan berbagai penggunaan $PORTvariabel, dan saya tidak tahu mengapa konfigurasi saya bekerja. Pada satu titik saya punya ini dalam naskah:

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

Dan dapatkan log jurnal seperti ini:

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

Pada dasarnya pertanyaan saya adalah: apa yang terjadi di sini? Ini terbang di hadapan bagaimana saya mengerti {}untuk bekerja dalam skrip bash. Dan mengapa saya bisa menggunakan ikal pada COREOS_PRIVATE_IPV4variabel (yang diekspor dari /etc/environment, tetapi tidak untuk PORT?

Daniel Buckmaster
sumber

Jawaban:

9

Ini didokumentasikan dalam systemd.service (1) . ${PORT}diperluas oleh systemd. Untuk meneruskan $ke shell Anda perlu menulis $$, jadi $${PORT}. Garis yang penting adalah ini:

Untuk melewati tanda dolar literal, gunakan "$$". Variabel yang nilainya tidak diketahui pada waktu ekspansi diperlakukan sebagai string kosong.

Uwe Geuder
sumber
Terima kasih untuk itu! Itu masuk akal sekarang, saya tidak melihat bahwa variabel dapat diganti oleh systemd berbeda dengan selama pelaksanaan skrip itu sendiri ...
Daniel Buckmaster
1
  1. jika konten PORT berasal dari beberapa variabel bash lain yang akan Anda hadapi, indirect referencesilakan coba:

    ${!PORT}
  2. Saya berasumsi Anda yakin shell Anda adalah Bash

Menepuk
sumber
Terima kasih atas tanggapannya! 1. PORTberasal dari baris dalam skrip export PORT=$(docker ...); 2. CoreOS dikirimkan dengan bash 4.2
Daniel Buckmaster
Apakah Anda mencoba ${!PORT}skrip Anda ??
Pat
Saya lakukan, dan tampaknya memberikan hasil yang sama (string kosong).
Daniel Buckmaster