Вопрос или проблема
У меня есть этот скрипт, который работает:
#! /usr/bin/bash
export SEQVAL=$(date +%s) && sed -i "s/^SEQ1=.*$/SEQ1=${SEQVAL}/" /etc/environment
systemctl restart ccs-srvapp-telemetry.service
Хоть убей, не могу заставить это работать правильно из unit файла.
Последний вариант ниже, но было несколько попыток с различными настройками, все провалились из-за того, что либо переменная не устанавливалась, либо что-то не корректно экранировалось в команде sed.
[Unit]
Description=restarts fluent bit with a new SEQ1 to force a logrotate
After=network.target
[Service]
Type=oneshot
EnvironmentFile=/etc/environment
ExecStart=/usr/bin/sh -c 'export SEQVAL=$(date +%s) && sed -i "s/^SEQ1=.*$/SEQ1=${SEQVAL}/" /etc/environment'
ExecStartPost=/bin/systemctl restart ccs-srvapp-telemety.service
[Install]
WantedBy=multi-user.target
Нужно быть осторожным при использовании $
в строках Exec
, так как systemd будет расширять форму ${variable}
везде, где она встречается, даже внутри строки в одинарных кавычках. Чтобы этого избежать, экранируйте $
с помощью $$
.
Также, %
используется для спецификаторов, поэтому %s
заменяется на имя оболочки. Экранируйте %
с помощью %%
.
ExecStart=/usr/bin/sh -c 'SEQVAL=$(date +%%s); sed -i "s/^SEQ1=.*/SEQ1=$${SEQVAL}/" /etc/environment'
но это тоже должно работать:
ExecStart=/usr/bin/sh -c 'sed -i "s/^SEQ1=.*/SEQ1=$(date +%%s)/" /etc/environment'
Также, учтите, что команды ExecStartPost
могут быть запущены до завершения команды ExecStart
. Они запускаются, когда команда инициирована. Если вы хотите быть уверены, что файл окружения обновлен, так как вы используете Type=oneshot
, вы можете просто использовать несколько строк ExecStart
, и они будут выполнены последовательно.
Ответ или решение
Вопрос о корректной синтаксической записи файла Systemd Unit, чтобы команды выполнялись ожидаемо, является типичной задачей для специалистов в области ИТ, особенно в контексте автоматизации и конфигурации систем. Чтобы достичь необходимого результата, важно уделить внимание деталям в корректировке синтаксиса и логики выполнения скриптов в файлах Unit.
Решение проблемы синтаксиса в файле Systemd Unit
Контекст проблемы
Имеется скрипт на Bash, который выполняет следующие действия:
- Устанавливает значение переменной
SEQVAL
, используя текущую временную метку. - Обновляет файл окружения
/etc/environment
с новым значениемSEQVAL
. - Перезапускает сервис
ccs-srvapp-telemetry.service
.
При переносе этого функционала в Unit-файл Systemd возникают ошибки с установкой переменной и корректным выполнением команды sed
. Основная причина ошибок связана с тем, как Systemd обрабатывает символы $
и %
.
Корректный синтаксис для Systemd Unit файла
Основные моменты
-
Экранирование символов: Systemd автоматически интерпретирует
${variable}
и%s
, даже внутри одиночных кавычек. Чтобы этого избежать, используйте$$
для$
и%%
для%
. -
Выполнение команд: Команды в секции
[Service]
выполняются указанным шеллом, поэтому важно указать правильный шелл, если требуется конкретная интерпретация команд. -
Последовательность выполнения: С учетом того, что используется
Type=oneshot
, командыExecStart
выполняются последовательно, что устраняет необходимость вExecStartPost
для данной задачи.
Пример исправленного Unit-файла:
[Unit]
Description=Обновление SEQ1 и перезапуск fluent bit для принудительного вращения логов
After=network.target
[Service]
Type=oneshot
EnvironmentFile=/etc/environment
ExecStart=/usr/bin/sh -c 'SEQVAL=$(date +%%s); sed -i "s/^SEQ1=.*/SEQ1=$${SEQVAL}/" /etc/environment'
ExecStart=/bin/systemctl restart ccs-srvapp-telemetry.service
[Install]
WantedBy=multi-user.target
Пояснения
-
ExecStart
и экранирование: Использование$$
вместо одного$
гарантирует, что переменная будет установлена корректно. Использование%%
вместо%
позволяет избежать подстановки имени шелла. -
ExecStart
вместоExecStartPost
: Достигается гарантированная последовательность выполнения команд, так как командыExecStart
выполняются одна за другой, и сервис не завершит выполнение, пока каждая из команд не завершится.
Заключение
Оптимизация файла Unit для Systemd требует внимания к деталям в синтаксисе и понимания механизмов работы Systemd. Правильное экранирование и организация команд внутри файла позволяют достичь желаемого результата без сбоев и ошибок.