Выход из системной строки

Если я запускаю эту команду

/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 в оболочку.

Другие вопросы по тегам