系统启动和终端启动程序之间的区别


9

我对程序之间的差异感到好奇。通过systemctl启用时,以systemd开头,而不是/etc/rc.local通过CLI或通过CLI进行启动。

例如,我最近在树莓派上使用shairport-sync。最初,我通过启用sudo systemctl的shairport-sync将shairport-sync设置为启动。

后来,我使用其中的功能在shairport-sync脚本运行之前和发布到连接的设备。

令我惊讶的是,这些脚本在执行shairport-sync时没有kill arecordaplay

但是,当我通过终端运行脚本时,脚本将执行并杀死arecordaplay

为了进一步迷惑自己,我shairport-sync通过终端杀死并启动了它,以查看正在发生的事情的输出。当我这样做时,脚本在设备连接并终止arecord并终止时按预期运行aplay。因此,作为一项修复,我禁用shairport-syncsysmtectl它并将其设置/etc/rc.local为作为快速修复运行。之后,reboot它按我的预期运行。

这使我相信,单独运行systemd的程序与通过/etc/rc.local或CLI 启动时运行的程序之间存在一些差异。

为什么会这样?这是因为运行级别不同吗?一些黑魔法?

设备连接到时运行的脚本shairport-sync如下:shairportstart.sh

#!/bin/sh
/usr/bin/sudo /bin/pkill arecord
if [ $(date +%H) -ge "18" -o $(date +%H) -le "7" ]; then
        /usr/bin/amixer set Speaker 40%
else
        /usr/bin/amixer set Speaker 100%
fi
/home/pi/shScripts/shairportfade.sh&

exit 0

这是渐变脚本: shairportfade.sh

#!/bin/sh
/usr/bin/amixer set Speaker 30-
for (( i=0; i<30; i++))
do  
    /usr/bin/amixer set Speaker 1+
done
exit 0

设备断开连接时运行的脚本shairport-sync如下:shairportend.sh

#!/bin/sh
/usr/bin/amixer set Speaker 70%
/usr/bin/arecord -D plughw:1 -f dat | /usr/bin/aplay -D plughw:1 -f dat&
exit 0

/var/log/syslog只有在最初以shairport-sync的身份运行时才发现以下错误systemd。当shairport-sync从CLI运行或/etc/rc.local没有错误存在。

Jan 24 00:38:45 raspberrypi shairport-sync[617]: sudo: no tty present and no askpass program specified

请注意,唯一的区别是shairport-sync设备连接或断开连接shairport-sync继续运行时的初始启动方式。


1
那些ps ... awk ... grep ...东西可能会被更简单的东西所取代pkill
感动的

@thrig最初该行要简单得多,但是由于它不起作用,所以我想我尝试使用其他方法来杀死仍然不起作用的实例。终止进程本身并不是问题,因为它起作用了,但仅在从用户登录名运行时才起作用
Brett Reinhard

你能显示清单/home/pi/shScripts/shairportfade.sh吗?
Michael D.

@MichaelD。我添加了淡入淡出脚本以及设备断开与shairport同步时执行的脚本
Brett Reinhard

@BrettReinhard从rc.local
Michael D.

Answers:


18

变体“为什么在systemd下事物表现不同?” 是一个常见问题。

任何时候从CLI运行而不是从systemd运行时,都有一些大范围的可能性来说明差异。

  1. 不同的环境变量在产生的过程中的环境变量部分中systemd记录它传递man systemd.exec环境变量。如果您想自己检查差异,可以使用systemd-run /path/to/binary,它将在您的应用程序中短暂运行,就像它是由systemd服务运行一样。您将得到类似的输出Running as unit: run-u160.service。然后journalctl -u run-u160.service,您可以查看输出。修改您的应用程序以转储接收到的环境变量,并将CLI运行与systemd运行进行比较。如果应用程序修改不方便,则可以使用systemd-run env它查看将传递的环境变量,并查看生成的日志记录。如果您尝试启动X11 GUI应用程序,则DISPLAY需要设置环境变量。在这种情况下,请考虑使用桌面环境的“自动启动”功能代替systemd
  2. 资源限制。请参阅参考资料man systemd.resource-control以获取可能限制资源消耗的配置值。使用systemctl show your-unit-unit.service检查影响您尝试启动该服务的完整配置的值。
  3. 非交互式外壳。您的bashCLI环境是一个交互式登录外壳。它源文件,就像.bashrcsystemd没有。除了设置环境变量外,这些脚本还可以执行许多其他操作,例如连接SSH代理,以便SSH操作不需要登录。另请参见登录外壳程序和非登录外壳程序之间的区别?
  4. 没有TTY。您的交互式会话已连接到TTY,某些程序在提示输入密码时会喜欢sudossh希望该TTY 。另请参见sudo:不存在tty且未指定askpass程序
  5. 相对路径与绝对路径。相对二进制工作在外壳中,但如中所述man systemd.service,第一个参数to ExecStart=必须是二进制的绝对路径。
  6. 受限的命令行语法。Shell CLI支持许多元字符,而systemd命令行语法却非常受限制。根据您的需求,您可以systemd通过在shell中显式运行命令来复制Shell语法:ExecStart=/bin/bash -c '/my/bash $(syntax) >/goes-here.txt'

这是系统在具有资源控制的一致环境中运行代码的功能。从长远来看,这有助于获得可重复的,稳定的结果,而不会占用过多的硬件。


还需要考虑MAC上下文(SELinux,...),功能,名称空间...
Bigon

2
@BrettReinhard不要调用从终端sudo更好地运行的shell脚本sudo shairportstart.sh,因为systemd以root身份运行脚本,因此无需以sudo身份运行。
Michael D.

1
我试图以多种方式解决问题,以了解正在发生的事情。最终,我最终要做的是将kill命令更改为/usr/bin/echo "mypassword" | /usr/bin/sudo /bin/pkill arecord。今天晚些时候,我将尝试将sudoecho命令删除到我的kill命令中,看看是否产生相同的结果。我的猜测是可行的,因为该错误似乎是由于该sudo命令未发送密码引起的。感谢您在理解为什么systemd与CLI 之间存在差异时所提供的帮助
Brett Reinhard

1
另一个不同之处可能很明显,但今天让我感到有些困扰:systemd试图跟踪服务的状态,如果它认为它已经处于活动状态,则不会启动它,因此,如果它认为服务正在运行。相比之下,通常编写init.d脚本来始终检查并尝试酌情启动服务。
乔什·凯利

1
@JoshKelley感谢您的提示。那不是systemd和CLI之间的区别,而是systemd和sysVinit init.d脚本之间的区别。
马克·斯托斯伯格
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.