Systemd 服务运行 bash 脚本失败

Systemd 服务运行 bash 脚本失败

在 Arch Linux 上,我尝试创建一个运行以下 Bash 脚本的 systemd 服务:

#!/bin/bash

/bin/xbindkeys &
/bin/setxkbmap -layout gb

在一些在线指导下,我创建了一个名为myfirst.servicein 的文件/etc/systemd/system来存储我的服务。以下是该文件的内容:

[Unit]
Description=Command Service

[Service]
ExecStart=/etc/startupjobscript
User=user1
Type=oneshot
Restart=on-abort
RemainAfterExit=yes

[Install]
WantedBy=multi-user.target

该服务应该执行/etc/startupjobscript,即 Bash 脚本。之后,我启用并启动了该服务:

systemctl enable myfirst
systemctl start myfirst

但由于某种原因它不起作用并显示它根本无法加载和运行。

编辑:这是sudo systemctl 状态 myfirst给我吗:

Warning: The unit file, source configuration file or drop-ins of myfirst.service changed on disk. Run 'systemctl daemon-reload' to reload units.
● myfirst.service - Command Service
     Loaded: loaded (/etc/systemd/system/myfirst.service; enabled; vendor preset: disabled)
     Active: failed (Result: exit-code) since Wed 2020-08-26 21:07:02 BST; 18min ago
    Process: 332 ExecStart=/etc/startupjobscript (code=exited, status=255/EXCEPTION)
   Main PID: 332 (code=exited, status=255/EXCEPTION)

Aug 26 21:07:01 archlinux systemd[1]: Starting Command Service...
Aug 26 21:07:02 archlinux startupjobscript[337]: Cannot open display "default display"
Aug 26 21:07:02 archlinux systemd[1]: myfirst.service: Main process exited, code=exited, status=255/EXCEPTION
Aug 26 21:07:02 archlinux systemd[1]: myfirst.service: Failed with result 'exit-code'.
Aug 26 21:07:02 archlinux systemd[1]: Failed to start Command Service.

答案1

当运行任何与 X 服务器通信的东西时,systemd 服务会变得有点棘手。有两种主要方法可以做到这一点:

  1. 运行用户服务
  2. 设置$DISPLAY并避免启动,直到graphical.target达到。

要将其作为用户服务运行,请myfirst.service移至~/.config/systemd/system/.然后删除User=并设置WantedBy=default.targetdefault.target当用户登录时会到达。有一天,graphical-session.target当用户登录到桌面环境时将会到达,但目前还不可用。相反,我们会default.target在用户登录时触发。如果您使用显示管理器,那么在此之前您可能有一个 x 会话。

[Unit]
Description=Command Service
After=default.target

[Service]
ExecStart=/bin/xbindkeys
ExecStartPost=/bin/setxkbmap -layout gb
Type=simple
Restart=on-abort

[Install]
WantedBy=default.target

--user使用本装置时请务必使用,例如:

systemctl --user daemon-reload
systemctl --user start myfirst.service
systemctl --user enable myfirst.service

要将其保留为系统服务,请保留该文件,/etc/systemd/system/并且您需要设置环境,以便它可以连接到 X 服务器。最后,一定要成功WantedBy=graphical.target。这可确保在 X 服务器启动之前它不会尝试连接到 X 服务器。但是我不确定它是否总是成功,因为在您登录之前我不确定 .Xauthority 是否有效。

[Unit]
Description=Command Service
After=graphical.target

[Service]
ExecStart=/bin/xbindkeys
ExecStartPost=/bin/setxkbmap -layout gb
Type=simple
User=user1
Environment=DISPLAY=:0
Environment=XAUTHORITY=/home/user1/.Xauthority
Restart=on-abort

[Install]
WantedBy=graphical.target

如果您有多个用户或多个显示器,系统范围的服务就会变得有点奇怪。建议做特定于用户的事情。如果您在桌面环境中,您可以echo $DISPLAYecho $XAUTHORITY弄清楚将这些变量设置为什么。


进行这些更改后,您需要告诉systemd您在尝试下一个之前阅读它们start。跑步:

systemctl daemon-reload

如果您一直在尝试,请务必systemctl disable myfirst.service先尝试,然后当您确定systemctl start myfirst.service有效时,您就可以了systemctl enable myfirst.service。 将在或enable中创建一个符号链接,以便在您重新启动时,您的服务被调用。为了避免在实验状态期间弄乱这些链接,请在准备好测试重新启动之前不要启用它。default.targetgraphical.target


/bin/xbindkeys &注意,我确实对你的 bash 脚本中的那一行有一个奇怪的怀疑。通常会xbindkeys永远运行吗?如果是这样,您可能需要更改ExecStart=为:

ExecStart=/bin/xbindkeys
ExecStartPost=/bin/setxkbmap -layout gb
Type=simple

我已经对上面建议的单位进行了这些更改。

这将确保 systemd 直接跟踪进程而不是分叉。因为Type=未设置为forking,我怀疑 bash 脚本将结束,并且 systemd 不会跟踪 PID,xbindkeys将其保留为孤立 PID,并且无法阻止它。如果您xbindkeys作为其中的一部分离开ExecStart,那么停止服务将终止 xbindkeys(我认为它现在将无法执行)。在这种情况下,您还需要进行设置,Type=simple因为oneshot不再适用。

相关内容