奇怪的事情:我创建了一个服务,它应该启动一个 springboot fat archive webserver。服务:
#!/bin/bash
[Unit]
Description=JalouWeb
[Service]
Type=simple
WorkingDirectory=/opt/jaloucontrol
ExecStart=/bin/bash jalouweb.sh
TimeoutStartSec=0
RestartSec=60
Restart=always
SyslogIdentifier=jalouweb
[Install]
WantedBy=multi-user.target
jalouweb.sh:
#! /bin/sh
#
java -Duser.timezone=Europe/Berlin -Dfile.encoding=UTF-8 -jar jcweb-0.0.1-SNAPSHOT.jar
以用户身份启动 jalouweb.sh 即可。执行 sudo -i 并以 root 身份启动 jalouweb.sh 。用户和 root 都可以成功调用 java -version。
但是当通过 systemctl 启动该服务时,我收到
... jalouweb.sh: Zeile 3: java: Kommando nicht gefunden.(<- command not found)
... systemd[1]: jalouweb.service: Main process exited, code=exited, status=127/n/a
一旦我将路径添加到 jalouweb.sh 中:
/opt/openjdk17/bin/java -Duser.timezone=Europe/Berlin...
systemctl 也成功了。但为什么? Afaik 在没有用户的情况下运行服务意味着以 root 身份运行它。 root 可以直接启动 sh 和 java。为什么systemctl需要显式路径?
编辑:我遵循了wenshuo的建议:尽管服务运行成功,但没有创建tmplog文件,但journalctl显示
systemd[1]: Started JalouWeb.
jalouweb[11189]:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin > /tmp/tmplog
systemd[1]: jalouweb.service: Succeeded.
看起来是这样,好像 echo 命令并不真正正确。但核心信息显示:No java in the path of the non-interactive root。
编辑2 @Stephane:查找或执行脚本没有问题。问题是,没有找到脚本中调用的java。我必须弄清楚,如何为 systemctl 的执行者提供路径或 JAVA_HOME。
答案1
bash some-path
在哪里some-path
不包含/
字符应该不是使用。这适用于其他几个类似 Korn 的 shell1 以及.
和source
builtins2 或许多类似 Bourne 的 shell,尽管具体情况更糟bash
。
bash
是 Bash 编程语言的解释器,就像perl
是编程语言的解释器一样Perl
。
bash /path/to/some/Bash/file
就像perl /path/to/some/Perl/file
你如何告诉bash
或perl
解释给定文件中的 Bash/Perl 代码而不是标准输入上的代码。
例如,它用于:
#! /bin/bash -
执行后,系统将其转换为/bin/bash - path/to/the/file
并bash
解释文件的内容。
与,正在执行,但未执行/bin/bash some-path
systemd
bash
bash
执行 some-path
³,它只是读取它并解释其中的 Bash 代码。
现在,当some-path
不包含任何/
,行为发生变化bash
。bash
首先将其解释为普通路径,因此这里是相对于其当前工作目录的路径,但如果找不到该文件,它会在环境$PATH
变量的目录组件中查找它(或者如果未设置)在某些默认搜索列表中)。
这种行为是允许虽然 POSIX 不要求,但 POSIX 只允许可执行文件在该过程中找到的文件。 Bash(至少是 5.2 版)甚至可以找到不可执行的文件,即使在 POSIX 模式下也是如此,这使得它不合规。
bash
在这里,您需要从该脚本所在的目录中解释该脚本,然后您需要:
WorkingDirectory=/path/to/that/dir
ExecStart=/bin/bash ./the-script
(请注意,./
确保路径包含 a 的前缀/
,并在当前工作目录中$PATH
由于某种原因丢失时禁用查找)。the-script
如果WorkingDirectory
未指定,则默认/
为系统服务,用户的主目录为用户服务。
或者您需要指定脚本的完整路径:
ExecStart=/bin/bash /path/to/that/dir/the-script
如果您缩进the-script
为可执行文件,并且由查找解释bash
并找到$PATH
,那么请确保它有一个#! /bin/bash -
shebang,它具有执行权限 ( chmod a+x
) 并且它存储$PATH
在systemd
.
并使用:
ExecStart=the-script
如果该文件是可执行的,我建议删除该.sh
扩展名。如果不是,并且它是用 Bash 语言编写的,我建议使用扩展,.bash
而不是.sh
如果它不是标准sh
语法,则会产生误导。
¹ 这是 zsh 在 sh 或 ksh 模拟中的情况,而 ksh 则可能是该错误功能的根源。
² 对于.
特殊的内置函数,这实际上比 POSIX 更糟糕需要 /
-less 路径被查找$PATH
(并回退到当前工作目录)。一些 shell 忽略的要求(包括不处于 POSIX 模式时的 bash)。
³ 这会有所不同,因为此处的bash -c the-script
文本the-script
作为内联 shell 代码供 bash 解释,bash 将其解释为一个简单的命令,导致它$PATH
查找可执行文件命令(脚本或非脚本)让它执行。
答案2
为了查找可执行文件,shell 将搜索$PATH
变量中列出的目录。如果$PATH
包含目录的路径名,则可以调用该目录中的可执行文件,而无需给出可执行文件的完整路径名。
您echo "$PATH"
可以在 shell 中看到当前的路径列表。就您而言,$PATH
所使用的systemctl
可能与交互式 shell 所使用的不同root
。
您可以使用以下命令查看$PATH
with中使用的值systemctl
ExecStart=/bin/echo "$PATH" > /tmp/tmplog
...在[Service]
单元文件的部分中。这会将$PATH
to的值写入/tmp/tmplog
。