Выход из системной строки
Если я запускаю эту команду
/bin/bash -c 'while true;do /usr/bin/etcdctl set my-container "{\"host\": \"1\", \"port\": $(/usr/bin/docker port my-container 5000 | cut -d":" -f2)}" --ttl 60;sleep 45;done'
Я получаю от etcd ожидаемое значение {"host":"1", "port":49155}
Но если я положу его в системный файл
ExecStart=/bin/bash -c 'while true;do /usr/bin/etcdctl set my-container "{\"host\": \"1\", \"port\": $(/usr/bin/docker port my-container 5000 | cut -d":" -f2)}" --ttl 60;sleep 45;done'
Я возвращаюсь {хост:1, порт: 49155}
Любая идея о том, почему экранирование отличается внутри файла? Как я могу это исправить? Спасибо!!
3 ответа
systemd-escape '\"a fun thing"\'
выход: \x5c\x22a\x20fun\x20thing\x22\x5c
[Service]
ExecStart=/bin/sh -c 'echo "\x5c\x22a\x20fun\x20thing\x22\x5c"'
распечатает a fun thing
Systemd работает не так, как вы сейчас знаете, отсюда и проблема с выходом. Фактически, systemd удаляет одинарные и двойные кавычки после их анализа. Этот факт прямо из документации (я тоже прошел через это, затем прочитал:D).
Решение, вызовите скрипт, который возвращает нужную вам информацию (с экранированными кавычками), если ваша цель это позволяет.
Короче говоря, все по-другому, потому что systemd выполняет собственное разбиение строк, удаление из памяти и расширение, а используемая логика не соответствует POSIX.
Вы все еще можете делать то, что хотите, но вам понадобится больше обратной косой черты:
ExecStart=/bin/bash -c '\
while :; do \
port=$(/usr/bin/docker port my-container 5000 | cut -d: -f2); \
/usr/bin/etcdctl set my-container "{\\\"host\\\": \\\"1\\\", \\\"port\\\": $port}" --ttl 60; \
sleep 45; \
done'
Обратите внимание на использование \\\"
за каждый буквальный "
символ в желаемом выходе.
Кстати - лично я не советую пытаться генерировать JSON с помощью конкатенации строк - он подвержен уязвимостям внедрения (если кто-то может поместить содержимое по своему выбору в выходные данные docker port
команда, они могут потенциально вставить другие пары ключ / значение в ваши данные, имея , "evil": true
быть в port
переменная). Этот класс проблем можно избежать с помощью jq
:
ExecStart=/bin/bash -c '\
while :; do \
port=$(/usr/bin/docker port my-container 5000 | cut -d: -f2); \
json=$(jq -nc \
--arg host 1 \
--arg port "$port" \
'{} | .host=$host | .port=($port | tonumber)'); \
/usr/bin/etcdctl set my-container "$json" --ttl 60; \
sleep 45; \
done'
Как счастливый побочный эффект, вышеупомянутое избегает необходимости каких-либо буквальных символов двойной кавычки (единственные используемые являются синтаксическими к копии sh
), поэтому нам не нужно передавать обратную косую черту из systemd в оболочку.