Вопрос или проблема
Я хотел бы узнать, существует ли определенное systemd
единица.
Это должно работать для:
- любого типа единицы (сервис, цель, монтирование и т.д.)
- работающей, отключенной или заблокированной единицы
Я знаю, что могу сделать это:
systemctl list-unit-files | grep "^my.target"
Но мне кажется, что должен быть лучший способ.
Опционально, я хотел бы иметь возможность выполнить эту проверку, просто указав my, без необходимости указывать “.service” (как для других systemctl
команд), что-то вроде
systemctl exists my
Я не знаю о нативном способе сделать это с помощью systemd, но вы могли бы (зло)использовать systemctl list-unit-files
:
systemctl-exists() {
[ $(systemctl list-unit-files "${1}*" | wc -l) -gt 3 ]
}
Это создает функцию “тестирования”, которую вы могли бы использовать так:
systemctl-exists my && echo my существует как systemd единица
Суффикс *
нужен для того, чтобы позволить systemd сопоставить данный аргумент с любым “типом” (сервис, цель или монтирование). Эта функция жестко закодирована для текущего вывода systemctl list-unit-files
, который включает как минимум три строки вывода (когда совпадающих единиц нет); больше, когда есть совпадающие единицы:
1. UNIT FILE STATE
(один или несколько соответствующих файлов единиц)
2. (пустая строка)
3. "%d файлов единиц перечислены."
Также имейте в виду, что подстановочный знак в конце может привести к ложноположительным результатам, если у вас есть файлы единиц с аналогичными префиксами — поиск “au” найдет “дурное золото” с “auditd”, “autofs” и другими, даже если вы ожидали только реальную вещь “au.service”. Уточняйте больше название сервиса, если вы его знаете: systemctl-exists au.service
сделает правильное.
Сначала я думал, что systemctl cat
будет работать как фильтр, но, похоже, он предполагает, что аргумент является сервисом, и поэтому не фильтрует соответствующим образом для других типов (например, цель или монтирование).
Обновленный ответ
Судя по всему, systemctl list-unit-files "$systemd_unit_name"
вернет статус выхода 0, если хотя бы одна единица* соответствующая "$systemd_unit_name"
существует, иначе вернет статус выхода 1.
* Примечание: systemctl list-unit-files ...
явно не перечисляет устройства (.device
).
Обновленные однострочники
Эти (обновленные) однострочники могут проверять существование единиц для любого типа единицы, включая сервисные единицы, целевые единицы, единицы сокетов, а также шаблонные единицы (например, [email protected]
) и шаблонные экземпляры единиц (например, [email protected])
.
### точное тестирование существования не-устройств
### тестирование, существует ли какая-либо единица (не включая устройства) с именем 'foo.service':
systemctl list-unit-files foo.service &>/dev/null && echo "эта единица существует" || echo "эта единица не существует"
### шаблонное сопоставление теста существования не-устройств
### тестирование, существует ли хотя бы одна единица (не включая устройства) с именем, соответствующим 'ssh*':
systemctl list-unit-files ssh* &>/dev/null && echo "хотя бы одна единица совпадает" || echo "нет совпадений единиц"
Для устройств используется команда systemctl status
. Несмотря на то, что systemctl
‘s документация упоминает, что статус выхода в пределах 0
и 3
указывает на существование единицы, а статус выхода 4
указывает на “такой единицы нет”, я заметил, что для имен, заканчивающихся на .device
, systemctl status doesntexist.device
по-прежнему возвращает статус выхода 3
. Поэтому следующий тест, специфичный для юнитов устройств, рассматривает статус выхода 0
как указание на то, что указанная единица устройства существует:
### точное тестирование существования устройства
# тестирует, существует ли какая-либо единица устройства с именем 'sys-module-fuse.device':
systemctl status sys-module-fuse.device &>/dev/null && echo "эта единица устройства существует" || echo "эта единица устройства не существует"
Ошибочный ответ
(По крайней мере с systemd версией 247, предыдущая версия этого ответа будет давать ненадежные результаты при тестировании шаблонной единицы или экземпляра шаблонной единицы (т.е. имя единицы как @
, [1] [2]))
Если статус выхода systemctl
равен 4
, то указанное имя единицы неизвестно systemd (т.е. запрашиваемая единица не существует).
Ошибочный однострочник
# пример однострочника для тестирования существования какой-либо единицы с именем 'foo.service':
# !!! НЕ РАБОТАЕТ НАДЕЖНО ДЛЯ ШАБЛОННЫХ ЕДИНИЦ ИЛИ ЭКЗЕМПЛЯРОВ ШАБЛОННЫХ ЕДИНИЦ
systemctl status foo.service &>/dev/null; if [[ $? == 4 ]]; then echo "эта единица не существует"; else echo "эта единица существует"; fi
Ошибочный скрипт на Bash
#!/bin/bash
set -euo pipefail
# файл test-systemd-unit-existence.sh
#
# этот скрипт проверяет, существует ли системная единица systemd под указанным именем.
#
# !!! НЕ РАБОТАЕТ НАДЕЖНО ДЛЯ ШАБЛОННЫХ ЕДИНИЦ ИЛИ ЭКЗЕМПЛЯРОВ ШАБЛОННЫХ ЕДИНИЦ
#
# если она существует, этот скрипт выводит "'$SYSTEMD_UNIT' существует под полным именем единицы '$SYSTEMD_UNIT_FULL_NAME'",
# иначе ("единица неизвестна"/"такой единицы нет") выводит "'$SYSTEMD_UNIT' не существует".
#
# Проверка осуществляется выполнением "systemctl status $SYSTEMD_UNIT",
# затем проверкой его статуса выхода
#
# см. https://www.freedesktop.org/software/systemd/man/systemctl.html#Exit%20status
#
# примеры использования:
# ./test-systemd-unit-existence.sh ssh.service
# ./test-systemd-unit-existence.sh ssh
# ./test-systemd-unit-existence.sh basic.target
# ./test-systemd-unit-existence.sh doesntexist.service
# ./test-systemd-unit-existence.sh uuidd
# ./test-systemd-unit-existence.sh uuidd.service
# ./test-systemd-unit-existence.sh uuidd.socket
# ./test-systemd-unit-existence.sh uuidd.target
SYSTEMD_UNIT="$1"
# использование "&>/dev/null" для подавления вывода stdout и stderr ("--quiet" только подавляет stdout).
# из-за "set -e" используется конструкция "... && true", чтобы избежать немедленного выхода скрипта при ожидаемом ненулевом коде выхода.
#
# "[...] Оболочка не выходит, если команда, которая завершилась неудачно,
# [...] часть любой команды, выполненной в списке && или ||
# [пока это не последняя команда в этом списке]"
#
# см. https://www.gnu.org/software/bash/manual/html_node/Lists.html
# см. "-e" на https://www.gnu.org/software/bash/manual/html_node/The-Set-Builtin.html
systemctl status "$SYSTEMD_UNIT" &>/dev/null && true
SYSTEMCTL_EXIT_STATUS="$?"
if [[ "$SYSTEMCTL_EXIT_STATUS" == 4 ]]; then
echo "'${SYSTEMD_UNIT}' не существует"
else
SYSTEMD_UNIT_FULL_NAME="$(systemctl show ${SYSTEMD_UNIT} --property=Id --value)"
echo "'${SYSTEMD_UNIT}' существует под полным именем единицы '${SYSTEMD_UNIT_FULL_NAME}'"
fi
Это проверит, загружен ли сервис или нет:
systemctl show --no-pager service_name.service | grep LoadState=loaded
echo $?
grep
вернет 1, если искомый термин найден.
Согласно руководству по systemctl, состояние загрузки может быть loaded
, not-found
, bad-setting
, error
, masked
.
Также существует LoadError
, который появится при ошибке загрузки, например:
LoadError=org.freedesktop.systemd1.NoSuchUnit "Единица service_name.service не найдена."
Используя systemctl cat
, вы получите ошибку, если единица не существует, примерно так:
# systemctl cat ntp >/dev/null; echo $?
Файлы для ntp.service не найдены.
1
# systemctl cat ntp >/dev/null 2>&1; echo $?
1
# systemctl cat ntpd >/dev/null 2>&1; echo $?
0
# systemctl cat ntpd.service >/dev/null 2>&1; echo $?
0
# systemctl cat ntpd.timer >/dev/null 2>&1; echo $?
1
Ответ или решение
Чтобы проверить, существует ли определенное системное единичное (unit) объект в systemd
, можно использовать несколько различных подходов. Важно понимать, что systemd
управляет различными типами единичных объектов, таких как службы (.service
), цели (.target
), точки монтирования (.mount
) и другие. Ниже приведены различные методы и рекомендации по проверке наличия единицы, включая специальные случаи для шаблонов.
Проверка существования единицы
-
Использование команды
systemctl list-unit-files
Для проверки существования единицы можно использовать команду
systemctl list-unit-files
. Эта команда возвращает список всех доступных единиц и их состояний, что позволяет вам легко искать нужные единицы. Например, следующий подход легко использовать для поиска конкретной единицы:systemctl list-unit-files | grep "^my.target"
Однако, нужно понимать, что такой метод может быть не самым эффективным, особенно если вы хотите проверить наличие единиц быстрее и проще.
-
Проверка с помощью ассоциативных команд
В более современных версиях
systemd
, таких как версия 247 и выше, можно просто выполнить:systemctl list-unit-files my* &>/dev/null && echo "единица существует" || echo "единица не существует"
Эта команда возвращает статус 0, если хотя бы одна единица, соответствующая шаблону
my*
, существует, и статус 1 в противном случае. -
Тестирование с помощью
systemctl status
Для проверки загрузки конкретной единицы можно использовать
systemctl status
. Это более надежный способ, поскольку он учитывает различные состояния единиц (например, загруженный, не найден и т.д.).systemctl status my.service &>/dev/null if [[ $? -eq 0 ]]; then echo "единица существует" else echo "единица не существует" fi
Здесь возвращаемое значение 0 указывает на то, что единица существует, в то время как любое другое значение будет значить, что единица не найдена.
-
Проверка доменных единиц
Для проверки существования доменных единиц (например,
device units
) следует использовать командуsystemctl status
, как показано ниже:systemctl status my.device &>/dev/null && echo "устройство существует" || echo "устройство не существует"
Несмотря на то что команда может возвращать различные статусы, важно учитывать, что статус 4 указывает на то, что единица не существует.
Проверка всех типов единиц
Вы можете расширить возможности проверки, создав универсальную функцию для проверки всех типов единиц:
systemctl-exists() {
unit=$1
if systemctl list-unit-files "$unit*" &>/dev/null; then
echo "единица $unit существует"
else
echo "единица $unit не существует"
fi
}
Эта функция воспользуется существующими инструментами systemctl
для обеспечения простоты проверки.
Заключение
В заключение, systemctl
предоставляет множество методов для проверки существования системных единиц. Выбор конкретного метода зависит от ваших потребностей и уровня требуемой детальности. Будь то прямой вызов systemctl status
, использование grep
для фильтрации вывода команды list-unit-files
, или написание собственной функции, все это поможет эффективно управлять системными единицами и обеспечивать их доступность на вашей системе.