ExecStart передал символ | программе: где systemd нужен shell

Команда экспорта работает в терминале: приложение печатает строки, фильтр оставляет нужные, результат попадает в файл. После переноса этой строки в ExecStart служба запускается иначе. В журнале программа ругается на аргумент с вертикальной чертой, а файл отчёта не появляется. Проверять права на файл здесь рано: перенаправление ещё никто не выполнял.

В терминале между нами и программой стоит оболочка. Она разбирает конвейер, открывает файл для перенаправления и соединяет процессы. Менеджер служб запускает программу по правилам ExecStart; наличие знакомых shell-символов само по себе не добавляет оболочку. Поэтому строка, визуально похожая на терминальную команду, может передать совсем другой список аргументов.

Сначала решить, нужен ли конвейер

Для журналирования отдельный shell часто не нужен. Программа пишет в стандартный вывод и ошибки, а systemd передаёт их в журнал. Фильтровать журнал удобнее при чтении, сохранив исходные сообщения. Такой unit легче сопровождать: у службы один главный процесс и понятный код завершения.

[Service]
ExecStart=/opt/report/bin/report --format=json
StandardOutput=journal
StandardError=journal

Если обработка действительно состоит из нескольких команд, вынесите её в исполняемый скрипт с подходящим shebang. В Bash можно явно включить pipefail, чтобы ошибка первой программы не исчезла за успешным фильтром. Тогда ExecStart содержит путь к скрипту, а синтаксис конвейера находится в файле, который можно запустить отдельно с теми же аргументами.

Для короткого действия оболочку можно вызвать явно. Например, у oneshot-задания, которому нужен простой последовательный запуск, будет ExecStart=/bin/sh -c 'command1 && command2'. Здесь уже нужно разбирать два уровня: правила строки unit и правила самой оболочки. Особое внимание требуется доллару и спецификаторам systemd. По мере усложнения выражения отдельный файл становится понятнее вложенных кавычек.

Как проверить исправление

Начните с systemctl cat report.service: он покажет unit вместе с drop-in, которые могли заменить команду. Затем проверьте файл через systemd-analyze verify и посмотрите журнал конкретного запуска. Синтаксическая проверка полезна, но содержимое скрипта и доступность его зависимостей она за вас не выполняет. В учебном окружении запустите ту же команду от пользователя службы.

Признак исправления — программа получила только свои аргументы, журнал содержит её сообщения, а ожидаемый результат создаётся тем компонентом, которому это поручено. Если конвейер оставлен, отдельно испортите входные данные и проверьте итоговый статус. Успешный фильтр не должен превращать неудачный экспорт в зелёный запуск. Так мы проверяем смысл действия, а не только исчезновение ошибки про символ |.

Продолжить практику

За одной настройкой unit обычно стоит весь путь сопровождения приложения: отдельный пользователь, права на данные, сеть, журналы и повторяемые операции. В программе курса «Linux и Bash для DevOps-инженеров» эти задачи собраны вокруг учебного сервера с приложением под systemd. В практике предусмотрены Bash-скрипты проверки состояния и резервного копирования, а также runbook для воспроизводимых поломок. Это подходящее продолжение, если хочется связать отдельные команды в понятный порядок диагностики.

Посмотреть программу курса

Источник: официальная документация.

Другие задачи по теме: Запуск и жизненный цикл служб systemd.

Продолжить на практике

  • Linux и Bash для DevOps-инженеров ↗

    Linux для работы с серверами: процессы, права, systemd, сеть, диски и логи. Автоматизируйте повседневные задачи на Bash и разберите типичные сбои сервиса — от занятого порта до переполненного диска.