systemd: Environment directive to set PATH
You can't use EnvVars
in Environment
directives. The whole Environment=
will be ignored. If you use EnvironmentFile=
, then the specified file will be loaded without substitution. So PATH=/local/bin:$PATH
would be exactly that, and this is probably not what you want.
Under CentOS7 the following works.
# /etc/systemd/system/nagios.service.d/env.conf
[Service]
Environment="PATH=/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin"
> sudo systemctl daemon-reload
> sudo systemctl restart nagios
> sudo cat /proc/28647/environ
...
PATH=/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin
...
systemd prepending /bin to Environment PATH
I created a test service that just printed out the path after setting Environment=
with a new path, and found it worked as expected on Ubuntu 16.04 with systemd 229.
I conclude that something in your script is pre-pending /bin to your environment.
Nothing in the systemd.exec
man page suggests that systemd is designed to behave the way you observe.
How to load environment variables for the process of a systemd service?
Environment can be set in systemd service file as below under Exec options
Environment=LD_LIBRARY_PATH=/usr/lib
Below is the official documentation of systemd Environment/EnvironmentFile usage
Environment=
Sets environment variables for executed processes. Takes a space-separated list of variable assignments. This option may be specified more than once, in which case all listed variables will be set. If the same variable is set twice, the later setting will override the earlier setting. If the empty string is assigned to this option, the list of environment variables is reset, all prior assignments have no effect. Variable expansion is not performed inside the strings, however, specifier expansion is possible. The $ character has no special meaning. If you need to assign a value containing spaces or the equals sign to a variable, use double quotes (") for the assignment.
Example:
Environment="VAR1=word1 word2" VAR2=word3 "VAR3=$word 5 6"
gives three variables "VAR1", "VAR2", "VAR3" with the values "word1 word2", "word3", "$word 5 6".
See environ(7) for details about environment variables.
EnvironmentFile=
Similar to Environment= but reads the environment variables from a text file. The text file should contain new-line-separated variable assignments. Empty lines, lines without an "=" separator, or lines starting with ; or # will be ignored, which may be used for commenting. A line ending with a backslash will be concatenated with the following one, allowing multiline variable definitions. The parser strips leading and trailing whitespace from the values of assignments, unless you use double quotes (").
The argument passed should be an absolute filename or wildcard expression, optionally prefixed with "-", which indicates that if the file does not exist, it will not be read and no error or warning message is logged. This option may be specified more than once in which case all specified files are read. If the empty string is assigned to this option, the list of file to read is reset, all prior assignments have no effect.
The files listed with this directive will be read shortly before the process is executed (more specifically, after all processes from a previous unit state terminated. This means you can generate these files in one unit state, and read it with this option in the next).
Settings from these files override settings made with Environment=. If the same variable is set twice from these files, the files will be read in the order they are specified and the later setting will override the earlier setting.
Read more here
Using variable in command path for ExecStart in systemd service
You can't use variables in the actual command. systemd.service:
The command to execute must be an absolute path name. It may contain
spaces, but control characters are not allowed.
You might wan't to wrap it in a shell command (which does parameter expansion):
ExecStart=/bin/bash -c '/${TESTEXTSERVICESFILES}/syslog/bin/nxlog -c ${TESTCONFDATA}/syslog/nxlog.conf'
systemd script - environment file updated by ExecStartPre
Since at least systemd 237, you can write an file in ExecStartPre=
that's read by EnvironmentFile=
before ExecStart=
runs as long as you prefix the file path with a dash (EnvironmentFile=-/some/path/.env
).
This appears to due to the timing of when the environment is evaluated. poettering says:
the env vars are determined only at execution time
So it's an error if EnvironmentFile=
is not defined when ExecStartPre=
is executed which is why it needs to be optional, but when the "execution time" of ExecStart=
comes, the EnvironmentFile is apparently re-checked and the environment variables set.
This could be better documented in man systemd.exec
.
You can also use an alternative approach which is suggested in man systemd.exec
where Environmentfile=
is documented:
Use one systemd service to write the environment file and a second one to consume it. Using either a Before=
or After=
relationship in the [Unit]
section, you can ensure that the service that writes the environment file is started first in the boot sequence.
How to use environment variables in a .service script
You are looking for EnvironmentFile=
directive in [Service]
section.
EnvironmentFile=/path/to/some/textFile
Read here for more info.
systemd env vars from an executable script
In order to have the variables from custom_script.sh
accessible from your Java process, you'll have to insert them into the environment somehow, in a way that systemd will be pleased with. The docs for the EnvironmentFile=
directive say that any line that is not a parameter assignment statement with an =
sign will be ignored. So we need to take your script and cook it down so that all we have left are the variables after running it.
What you can do is create an auxiliary "distillery" service that sources your custom_script.sh
file and prints every value in the environment to another file called custom_script.env
. Then you can provide the "distilled" environment file to the Java process in the EnvironmentFile
directive.
So if your original service adds After=
and Requires=
like this,
[Unit]
Description=My description
After=custom-script-distillery
Requires=custom-script-distillery
[Service]
Type=simple
User=myuser
EnvironmentFile=/path/to/my/custom_script.env
ExecStart=/path/to/my/start_script.sh
ExecStop=/path/to/my/stop_script.sh
ExecReload=/bin/kill -HUP $MAINPID
KillMode=process
Restart=on-failure
RestartSec=30s
[Install]
WantedBy=multi-user.target
Then the distillery could look like this:
[Unit]
Description=My service to distill custom_script.sh to an EnvironmentFile
[Service]
Type=oneshot
RemainAfterExit=yes
ExecStart=/bin/bash -c 'set -o allexport; source /path/to/my/custom_script.sh; set +o allexport; unset IFS; set | grep -v "^BASH" > /path/to/my/custom_script.env'
Related Topics
How to Catch Duplicate Entries in Text File in Linux
The Meaning of Real, User, and Sys in Output of Linux Time Command
Using the Linux Sysfs_Notify Call
How to Read the Last Line of a Text File into a Variable Using Bash
Retrieve Plain Text Script from Compiled Bash Script
Rtnetlink Answers :No Such File or Directory Error
How to Protect My Process from Being Killed
System D-Bus Does Not Allow Punching Out Ownership with Conf Files
Finding an Ip Address from an Interface Name
Extract List of File Names in a Zip Archive When 'Unzip -L'
How to Pass All Arguments with Xargs in Middle of Command in Linux
Grep String Inside Double Quotes
What Unit Is Used to Display Redis CPU Usage
Compiling a Linux Program for Arm Architecture - Running on a Host Os
Determine Usb Device File Path
Cannot Clone Repository: Fatal: R Any Gitolite-Admin Gitolite Denied by Fallthru