systemctlは実行可能ファイルを見つけることができませんが、rootは見つかりませんか?

systemctlは実行可能ファイルを見つけることができませんが、rootは見つかりませんか?

奇妙なこと:私はspringboot fat archive Webサーバーを起動するサービスを作成しました。提供する:

#!/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を実行し、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として実行することを意味します。ルートは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コマンドが実際に正しくないようです。ただし、重要な情報は次のとおりです。非対話型ルートパスにjavaがありません。


編集2 @Stephane:スクリプトの検索または実行に問題はありません。問題は、スクリプトから呼び出されたJavaが見つからないことです。 systemctlの実行者にパスまたはJAVA_HOMEを提供する方法を理解する必要があります。

答え1

bash some-path

どこsome-path/次の文字は含まれていません。いいえ使用。状況が悪い場合でも、これはいくつかの異なるKorn様シェル1と組み込み.2、sourceまたは多くのBourne様シェルに適用されますbash

bashこれは、プログラミング言語のインタプリタと同様に、Bashプログラミングperl言語のインタプリタですPerl

bash /path/to/some/Bash/file標準入力のコードではなく、与えられたファイルのBash / Perlコードをperl /path/to/some/Perl/file話すか解釈する方法bashと同じです。perl

たとえば、次の目的に使用されます。

#! /bin/bash -

実行後、システムはそれをファイルの内容に変換して/bin/bash - path/to/the/file解釈します。bash

そして実行中ですが、実行されません。/bin/bash some-pathsystemdbashbash実装する some-path3、ちょうどそれを読み、その中のBashコードを解釈します。

今、いつsome-path/動作の変更は含まれていませんbashbashまず、通常のパスとして解釈されるので、ここでは現在の作業ディレクトリとは対照的ですが、ファイルが見つからない場合は、$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解釈してfindとしてbash見つけた場合は、実行権限()を持つs​​hebangがあり、に保存されていることを$PATH確認してください。#! /bin/bash -chmod a+x$PATHsystemd

そして、以下を使用してください:

ExecStart=the-script

ファイルが実行可能な場合は、拡張子を削除することをお勧めします.sh。それ以外の場合、Bash言語で書かれている場合は、.bash代わりに拡張機能を使用することをお勧めします。.sh標準構文でない場合は誤解を招く可能性がありますsh


¹これはshまたはkshエミュレーションのzshの場合であり、kshがこのバグ機能のソースである可能性があります。

².これは実際に特別な組み込み機能の場合はPOSIXよりも悪いです。必要 /- 少ないパスが検索されます$PATH(現在の作業ディレクトリに置き換えられます)。一部のシェルでは、要件は無視されます(POSIXモードでない場合はbashを含む)。

³ここにあるbash -c the-scriptテキストはthe-scriptbashによってインラインシェルコードとして解釈され、単純なコマンドとして解釈されるので違いがあります$PATH実行可能ファイルこれを行うコマンド(スクリプトまたは非スクリプト)実装する

答え2

実行可能ファイルを見つけるために、シェルは$PATH変数にリストされたディレクトリを検索します。$PATHディレクトリのパス名を含めると、実行可能ファイルのフルパス名を指定せずにそのディレクトリから実行可能ファイルを呼び出すことができます。

echo "$PATH"シェルで現在のパスのリストを表示できます。あなたの場合は、インタラクティブシェルで使用するのとは異なる場合が$PATHあります。systemctlroot

$PATH次のコマンドを使用して、で使用されている値を表示できます。systemctl

ExecStart=/bin/echo "$PATH" > /tmp/tmplog

...[Service]ユニットファイルのセクションにあります。$PATHこれにより、の値がに書き込まれます/tmp/tmplog

関連情報