我想知道某个systemd
单位是否存在。
这应该适用于:
- 任何类型的单位(服务、目标、安装……)
- 运行、禁用或屏蔽的单元
我知道我可以这样做:
systemctl list-unit-files | grep "^my.target"
但感觉必须有更好的方法。
或者,我希望能够通过指定来运行此检查我的无需指定“.service”(就像其他systemctl
命令一样),例如
systemctl exists my
答案1
我不知道本地 systemd 的方式来做到这一点,但你可以(ab)使用systemctl list-unit-files
:
systemctl-exists() {
[ $(systemctl list-unit-files "${1}*" | wc -l) -gt 3 ]
}
这将创建一个“测试”函数,您可以像这样使用:
systemctl-exists my && echo my exists as a systemd unit
后缀*
允许 systemd 将给定参数与任何“类型”(服务、目标或安装)相匹配。该函数被硬编码为当前systemctl list-unit-files
输出,其中至少包含三行输出(当不存在匹配单元时);当有匹配单位时更多:
1. UNIT FILE STATE
(one or more matching unit files)
2. (a blank line)
3. "%d unit files listed."
另请注意,如果您有具有相似前缀的单元文件,末尾的通配符可能会导致误报 - 搜索“au”将找到带有“auditd”、“autofs”等的傻瓜黄金,即使您只是期望真正的“au.service”。如果您知道的话,请拼写出更多的服务名称:systemctl-exists au.service
将做正确的事情。
我最初认为systemctl cat
可以用作过滤器,但它显然假设参数是服务因此无法适当过滤其他类型(例如目标或安装)。
答案2
更新的答案
显然,systemctl list-unit-files "$systemd_unit_name"
, 将会返回退出状态0如果至少有一个单元*匹配"$systemd_unit_name"
存在,否则将返回退出状态1。
*注:systemctl list-unit-files ...
显然没有列出设备单位( .device
)。
更新了单线
这些(更新的)oneliners 可以测试任何类型单元的单元存在性,包括服务单元、目标单元、套接字单元、也模板单元(例如[email protected]
)和模板实例单元(例如[email protected])
.
### exact non-device unit existence test
### test if some unit (not including device units) named 'foo.service' exists:
systemctl list-unit-files foo.service &>/dev/null && echo "this unit exists" || echo "this unit does not exist"
### pattern match non-devixe unit existence test
### test if at least one unit (not including device units) with a name matching 'ssh*' exists:
systemctl list-unit-files ssh* &>/dev/null && echo "at least one unit matches" || echo "no unit matches"
对于设备单位,systemctl status
则使用该命令。尽管systemctl
的文档提到0
和中的退出状态3
表示存在一个单元,退出状态4
表示“没有这样的单元”,我注意到对于.device
特别以结尾的名称,systemctl status doesntexist.device
仍然返回退出状态3
。因此,以下特定于设备单元的测试将退出状态0
视为指定设备单元存在的指示:
### exact device unit existence test
# test if some device unit named 'sys-module-fuse.device' exists:
systemctl status sys-module-fuse.device &>/dev/null && echo "this device unit exists" || echo "this device unit does not exist"
有缺陷的答案
(至少与系统版本 247,这个答案的先前版本在测试时会给出不可靠的结果模板单元或者模板单元实例(即单位名称为@
,[1] [2]))
如果systemctl
的退出状态为4
,则指定的单位名称未知系统(即,请求的单元不存在)。
有缺陷的单线
# example oneliner to test on the existence of some unit named 'foo.service':
# !!! DOES NO WORK RELIABLY FOR TEMPLATE UNITS OR TEMPLATE UNIT INSTANCES
systemctl status foo.service &>/dev/null; if [[ $? == 4 ]]; then echo "this unit does not exist"; else echo "this unit exists"; fi
有缺陷的 Bash 脚本
#!/bin/bash
set -euo pipefail
# file test-systemd-unit-existence.sh
#
# this script tests if there exists a systemd system unit under the provided name.
#
# !!! DOES NO WORK RELIABLY FOR TEMPLATE UNITS OR TEMPLATE UNIT INSTANCES
#
# if it exists, this script echoes "'$SYSTEMD_UNIT' exists under the full unit name '$SYSTEMD_UNIT_FULL_NAME'",
# otherwise ("unit unknown"/"no such unit") echoes "'$SYSTEMD_UNIT' does not exist".
#
# the test is accomplished by executing "systemctl status $SYSTEMD_UNIT",
# then checking its exit status
#
# see https://www.freedesktop.org/software/systemd/man/systemctl.html#Exit%20status
#
# usage examples:
# ./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"
# using "&>/dev/null" to discard stdout and stderr output ("--quiet" only discards stdout).
# due to "set -e", using " ... && true" construct to avoid script from
# exiting immediately on expectable nonzero exit code.
#
# "[...] The shell does not exit if the command that fails is
# [...] part of any command executed in a && or || list
# [as long as it isn't the final command in this list]"
#
# see https://www.gnu.org/software/bash/manual/html_node/Lists.html
# see "-e" at 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}' does not exist"
else
SYSTEMD_UNIT_FULL_NAME="$(systemctl show ${SYSTEMD_UNIT} --property=Id --value)"
echo "'${SYSTEMD_UNIT}' exists under the full unit name '${SYSTEMD_UNIT_FULL_NAME}'"
fi