我正在创建一个 systemd 脚本来根据需要运行程序。当我运行它时,工作目录可能不存在。因此,我想创建该目录作为脚本的一部分。但是,我收到错误,因为指定的工作目录不存在:
[Service]
User=Inplant
Group=Inplant
ExecStartPre=/bin/mkdir -p /home/inplant/IPSdevice/JAI1
WorkingDirectory=~/IPSdevice/JAI1
ExecStart=~/IPSdevice JAI1
有没有办法创建工作目录作为 systemd 脚本的一部分。我想运行如下程序:
mkdir ~/IPSdevice/JAI1; cd ~/IPSdevice/JAI1; ~/IPSdevice JAI1
通过将波浪号更改为路径,我能够解决第一个问题。现在我遇到了一个不同的问题:
Aug 06 09:48:53 ubuntu systemd[1]: Started JAI Device Service.
-- Subject: Unit app-ips-jai1.service has finished start-up
-- Defined-By: systemd
-- Support: http://lists.freedesktop.org/mailman/listinfo/systemd-devel
--
-- Unit app-ips-jai1.service has finished starting up.
--
-- The start-up result is done.
Aug 06 09:48:53 ubuntu systemd[103782]: app-ips-jai1.service: Failed at step CHDIR spawning /home/inplant/IPSdevice/IPSdevice: No such file or directory
-- Subject: Process /home/inplant/IPSdevice/IPSdevice could not be executed
-- Defined-By: systemd
-- Support: http://lists.freedesktop.org/mailman/listinfo/systemd-devel
--
-- The process /home/inplant/IPSdevice/IPSdevice could not be executed and failed.
--
-- The error number returned by this process is 2.
系统脚本是:
[Unit]
Description=JAI Device Service
# When systemd stops or restarts the app.service, the action is propagated to this unit
PartOf=app.service
# Start this unit after the app.service start
After=app-ips.service
[Service]
# Pretend that the component is running
RuntimeDirectory=IPS-JAI1
User=inplant
Group=inplant
ExecStartPre=mkdir -p /home/inplant/IPSdevice/JAI1
WorkingDirectory=/home/inplant/IPSdevice/JAI1
#ExecStart=/home/inplant/IPSdevice JAI1 > /dev/nul 2>&1 & echo $! > /var/run/jai1.pid
ExecStart=/home/inplant/IPSdevice/IPSdevice JAI1
# Restart the service on non-zero exit code when terminated by a signal other than SIGHUP, SIGINT, SIGTERM or SIGPIPE
#Restart=on-failure
[Install]
# This unit should start when app.service is starting
WantedBy=app-ips.service
通常,我通过以用户“inplant”身份登录并执行以下命令来启动服务:
cd ~/IPSdevice
mkdir -p JAI
cd JAI
../IPSdevice JAI
答案1
部分问题是您使用~
, systemd 不扩展~
或~user
,因此您需要在命令中指定完整路径。
此外,您不能真正在 中 创建目录,ExecStartPre=
然后在 中 使用它WorkingDirectory=
,因为 systemd 会WorkingDirectory=
在执行任何命令之前进行检查。 (事实上,所有命令都ExecStartPre=
将在同一目录下运行。)
为了实现这一点,请使用 shell 脚本来ExecStart=
准备环境和exec
守护程序。
例如,创建一个/home/inplant/start_inplant.sh
:
#!/bin/sh
set -eu
mkdir -p /home/inplant/IPSdevice/"$1"
cd /home/inplant/IPSdevice/"$1"
exec /home/inplant/IPSdevice/IPSdevice "$1"
在你的单元文件中,使用:
[服务] 运行时目录=IPS-JAI1 用户=体内 组=种植体 环境=LD_LIBRARY_PATH=/opt/pleora/ebus_sdk/Ubuntu-x86_64/lib:/opt/pleora/ebus_sdk/Ubuntu-x86_64/lib/genicam/bin/Linux64_x64:/opt/xview2_64/lib/:/opt/GO_SDK/lib /linux_x64 环境=GENICAM_ROOT_V3_0=/opt/pleora/ebus_sdk/Ubuntu-x86_64/lib/genicam ExecStart=/home/inplant/start_inplant.sh JAI1 # 当被 SIGHUP、SIGINT、SIGTERM 或 SIGPIPE 以外的信号终止时,以非零退出代码重新启动服务 重新启动=失败时
不需要WorkingDirectory=
或ExecStartPre=
在您的单位文件中。您还可以决定在 shell 脚本本身中导出环境变量,由您决定是否喜欢其中之一。
一个重要的部分是使用exec
在 shell 脚本中。这使得 shell 将自身替换为正在执行的程序,以便该程序在与 shell 启动时相同的 PID 下运行。这很重要,因为 systemd 将使用该 PID 来控制守护进程(例如,在停止服务时杀死它),因此您希望它是守护进程而不是 shell 脚本。另外,您不想让额外的 shell 进程运行,只是无缘无故地占用空间。
请注意,您实际上能~
在你的start_inplant.sh
shell 脚本中使用。由于它是 shell 脚本,因此它将允许并执行 shell 通常执行的所有扩展。
请注意您对这个问题的其他答案:
这实际上不起作用:
ExecStartPre=cd /home/inplant/IPSdevice/JAI1
systemd 并不真正运行 shell 命令(并且cd
是内置的 shell。)这仅在存在/bin/cd
或/usr/bin/cd
二进制文件时才起作用,但不存在这样的事情(因为更改目录仅影响当前进程,因此外部二进制文件没有意义,因为它只会影响自身并退出,你不会看到它的效果。)
即使您使用 shell 显式运行该命令:
ExecStartPre=/bin/sh -c "cd /home/inplant/IPSdevice/JAI1"
这也不起作用,因为这只会影响当前的 shell,并且更改目录的效果不会传播到任何其他命令,特别是该ExecStart=
命令。
我不知道这是怎么回事工作文件对你来说,因为如果命令ExecStartPre=
失败,systemd 不会真正运行单元文件,尽管我可以看到 systemd 忽略这一行(并记录它),因为它认为它的语法不正确(systemd 的版本需要它们运行的命令的完整路径,直到最近的版本)并且它只是跳过该行并转到下一行。
如果确实如此,那么您的守护进程正在运行,/home/inplant/IPSdevice/
而不是/home/inplant/IPSdevice/JAI1/
,也许它在那里工作得很好,我对此不会感到惊讶,因为守护进程(特别是写得好的守护进程)并不真正关心哪个守护进程他们开始的目录,所以也许这个要求一开始并不存在。
此外,该命令:
ExecStartPre=/bin/chown inplant.inplant /home/inplant/IPSdevice/JAI1
应该是不必要的,因为默认情况下命令将使用和ExecStartPre=
指定的凭据运行,因此您已经使用该用户创建一个目录(特别是,这意味着该用户需要拥有创建该目录的权限),因此无需更改所有权,因为这应该已经是创建的目录的所有权。User=
Group=
mkdir
inplant
答案2
波形符是特定于 shell 的扩展,但单元文件中指定的指令不使用 shell 运行。您必须将 替换~
为目录的绝对路径。 Systemd 正在寻找一个名称为 的工作目录~/IPSDevice/JAI1
。
答案3
我发现即使 ExecStartPre 创建了工作目录,也无法将其设置为不存在的目录。我必须在 ExecStartPre 指令中使用 cd 来更改到创建目录后的目录。这是工作文件:
[Unit]
Description=JAI Device Service
# When systemd stops or restarts the app.service, the action is propagated to this unit
PartOf=app.service
# Start this unit after the app.service start
After=app-ips.service
[Service]
RuntimeDirectory=IPS-JAI1
User=inplant
Group=inplant
Environment=LD_LIBRARY_PATH=/opt/pleora/ebus_sdk/Ubuntu-x86_64/lib:/opt/pleora/ebus_sdk/Ubuntu-x86_64/lib/genicam/bin/Linux64_x64:/opt/xview2_64/lib/:/opt/GO_SDK/lib/linux_x64
Environment=GENICAM_ROOT_V3_0=/opt/pleora/ebus_sdk/Ubuntu-x86_64/lib/genicam
ExecStartPre=/bin/mkdir -p /home/inplant/IPSdevice/JAI1
ExecStartPre=/bin/chown inplant.inplant /home/inplant/IPSdevice/JAI1
ExecStartPre=cd /home/inplant/IPSdevice/JAI1
ExecStartPre=/bin/ls -al /home/inplant/IPSdevice/JAI1
WorkingDirectory=/home/inplant/IPSdevice/
ExecStart=/home/inplant/IPSdevice/IPSdevice JAI1
# Restart the service on non-zero exit code when terminated by a signal other than SIGHUP, SIGINT, SIGTERM or SIGPIPE
Restart=on-failure
[Install]
# This unit should start when app.service is starting
WantedBy=app-ips.service
```