Когда я выполняю
systemctl list-units —all —state=loaded
Я получаю вывод для каждого юнита с колонками
UNIT LOAD ACTIVE SUB DESCRIPTION
Мне нужно только UNIT в выводе.
Я пробовал добавить —property=UNIT, но все равно выводятся все колонки. Пробовал —output=json-pretty, не сработало.
Мне нужно сопоставить определенный юнит в выводе, но мое регулярное выражение не работает, поэтому будет полезно, если я получу только список юнитов, чтобы было легче сравнивать строки.
Регулярное выражение, которое я использую: fgrep «input_from_user».service
Любые предложения по регулярному выражению или команде?
Попробуйте эту однострочную команду:
systemctl show ‘*’ —state=loaded —property=Id —value —no-pager | grep . | sort | uniq
Объяснение
- systemctl предоставляет команду show:
- ‘*’ выбирает все юниты (по моему наблюдению). Без ‘*’ systemctl show просто покажет информацию о самом системном менеджере, а не о юнитах, которыми он управляет.
- —state=loaded выбирает только те юниты, которые находятся в состоянии loaded, как указано в вашем вопросе (… каждое выбранное состояние загрузки юнита можно добавить к выводу, добавив —property=LoadState)
- —property=Id добавляет название юнита (Id) к выводу (см. также —property документацию).
- —value удаляет ключи свойств из вывода, и показывает только значения свойств (т.е. Id=foo.service становится foo.service)
- —no-pager указывает systemctl не использовать пейджер (… добавлено на случай, если systemctl не замечает, что он используется внутри конвейера)
- Вывод systemctl show … затем пропускается через … | grep . | sort | uniq:
- grep . отфильтровывает любые пустые строки. Это делает дальнейшую обработку более стабильной
- sort сортирует все названия юнитов в алфавитном порядке
- uniq гарантирует, что каждое название юнита указано не более одного раза (добавлено на всякий случай).
Как только у вас есть JSON вывод, вы можете использовать jq или Python или что-то, что понимает JSON. Например, фильтрация с использованием jq:
systemctl list-units —output json | jq -r —arg pattern input_from_user ‘.[].unit | select(test($pattern))’
Это не задокументировано, но это было добавлено в мае 2020 года как общая функция преобразования табличного вывода в JSON; git grep output_table указывает, что это должно работать для list-units, list-unit-files и list-machines.
Пример:
% systemctl list-units —output json | jq -r —arg pattern network ‘.[].unit | select(test($pattern))’network-online.targetnetwork.target
Чуть быстрее версии @Abdull (в два раза быстрее в моем случае):
systemctl show ‘*.service’ —state=loaded —property=Id —value | sort -u
Решение с —output json очень быстрое, но не работает на некоторых старых версиях systemd (в моем случае на Ubuntu 20.04).
Ответ или решение
Вопрос относительно извлечения только имен юнитов с использованием команды systemctl на первый взгляд может показаться простым, но в действительности он требует понимания особенностей работы с системными сервисами на базе systemd. В этой статье я подробно объясню, как можно осуществить данную задачу, и предложу несколько подходов для её решения.
Теория
systemctl — это основной инструмент управления systemd в Linux-системах. Команда systemctl list-units —all —state=loaded отображает юниты, которые загружены в систему.
Однако, по умолчанию это делает вывод в табличной форме, включая несколько колонок: UNIT, LOAD, ACTIVE, SUB, и DESCRIPTION. В основах работы с systemctl предусмотрены опции, которые на первый взгляд могут казаться подходящими для фильтрации вывода, такие как —property и —output=json-pretty, но они не всегда помогают в достижении нужного результата из-за ограничений в самих возможностях команды.
Примеры использования
Для того чтобы извлечь только имена юнитов, необходимо выйти за пределы привычной работы с systemctl и комбинировать её с другими утилитами Unix, а именно функтором pipe (|), командами grep, sort, uniq, а также использовать параметры как —value, которые могут упростить вывод.
Использование команды systemctl show
Один из эффективных способов это сделать — использование команды systemctl show, которая позволяет запросить необходимые данные о каждом юните в более развернутом формате:
systemctl show ‘*’ —state=loaded —property=Id —value —no-pager | grep . | sort | uniq
Объяснение этого подхода:
- systemctl show ‘*’ — выбирает все юниты. Без параметра звездочки, команда покажет информацию только для самого менеджера systemd, а не для управляемых им юнитов.
- —state=loaded — фильтрует только загруженные юниты.
- —property=Id — добавляет вывод только с именами юнитов.
- —value — удаляет ключи свойств из вывода, оставляя только значения, которые нас интересуют.
- —no-pager — отключает использование пейджера для вывода, что полезно при передаче данных в следующую команду через pipe.
Также важно отметить использование комбинаций grep, sort, и uniq для удаления пустых строк, сортировки выходного массива и исключения дублей, соответственно.
Альтернативный подход: использование JSON и jq
В случае, если версия systemd поддерживает вывод в JSON, это облегчает последующую обработку. Пример команды:
systemctl list-units —output=json | jq -r ‘.[].unit’
Почему этот метод эффективен:
- Вывод в JSON более структурирован и легко поддается парсингу инструментами, такими как jq, что значительно упрощает процесс извлечения данных.
- jq -r ‘.[].unit’ — позволяет извлечь только значения полей unit для каждого элемента JSON-массива.
Замечательно, если ваша версия системы поддерживает JSON-вывод, так как это ускоряет процесс. Однако на более старых системах, например Ubuntu 20.04, этот подход может быть недоступен.
Применение на практике
Знания о том, как извлечь специфические части данных с помощью systemd команд, полезны для множества задач в IT сфере. Например, у вас может возникнуть необходимость автоматизации процессов управления сервисами на сервере, поддержки их актуального состояния или мониторинга. Этот подход также может быть полезен администратору для регулярной проверки системного состояния, где вывод имен юнитов может быть использован для их последующего управления (запуска, остановки, перезапуска).
Кроме того, знание того, как использовать grep с регулярными выражениями при работе с таким выводом, помогает отбирать юниты по определённым шаблонам. Например, fgrep «input_from_user».service был упомянут как способ фильтрации юнитов по конкретному пользователю. Владение такими навыками позволит вам быстрее разрешать задачи без лишних манипуляций.
Подводя итог, извлечение имен юнитов из вывода systemctl — это не только вопрос корректного использования системных инструментов, но и умения комбинировать их для получения конкретного результата. Разные системы, разные версии systemd — все это вносит свои коррективы в то, как вы можете решать подобные задачи, однако базовые принципы остаются неизменными: знание системы и умение адаптировать команды под нужды задачи.