You cannot directly assign environment variables like
PATH in the
[Path] section of a
.path unit file because systemd does not support variable expansion there. The only reliable workaround is to define the path condition in the unit file and let the triggered service handle the environment setup via
Environment= directives, ensuring your scripts find the correct executables when invoked.
Why PATH Cannot Be Set in .path Units
Systemd unit files are parsed differently depending on their type. In
.service units, you can use
Environment= or
EnvironmentFile= to inject variables into the process context. However, the
.path unit type is designed solely for monitoring filesystem events. Its configuration options are limited to
PathExists=,
PathChanged=,
PathModified=, and related triggers. There is no directive to set environment variables for the unit itself because the unit does not run a process; it only watches for changes.
Attempting to add
Environment=PATH=/usr/local/bin:$PATH inside a
[Path] section will be ignored by systemd or may cause a parsing error depending on the version. This limitation exists because the path unit runs as part of the system manager’s main process, which has a fixed, minimal environment. It does not spawn a shell or a service instance until the trigger fires. Therefore, any variable manipulation must happen in the context where the actual work is performed: the triggered service.
The Standard Workaround: Triggered Services
The most robust approach is to decouple the monitoring logic from the execution logic. You keep the
.path unit simple, focusing only on detecting the event. Then, you create a corresponding
.service unit that handles the actual task. This service unit can fully utilize systemd’s environment management features.
When the
.path unit detects a change, it activates the associated
.service. At that point, the service starts with its own environment, which you can configure precisely. This method ensures that your scripts have access to all necessary tools and libraries without interfering with the system-wide environment or the systemd manager itself.
For example, if you need a script located in
/opt/scripts to run, you do not try to add
/opt/scripts to the
PATH in the
.path file. Instead, you ensure the
.service file sets the environment correctly before executing the command. This separation also makes debugging easier, as you can inspect the service logs independently of the path monitoring logs.
Implementing Environment Variables in the Service Unit
To implement this workaround, you must edit the
.service file that corresponds to your
.path trigger. Use the
Environment= directive within the
[Service] section to define your custom
PATH or other variables. Systemd supports both absolute assignments and appending to existing paths.
Here is how you might structure the
[Service] section:
[Service]
Type=oneshot
Environment="PATH=/usr/local/custom/bin:/usr/bin:/bin"
ExecStart=/usr/local/custom/bin/my_script.sh
In this example, the
my_script.sh script will execute with a modified
PATH that includes
/usr/local/custom/bin at the beginning. This ensures that any executable named in the script resolves to the custom version first. If you need to append to the default path, you can use
Environment="PATH=$PATH:/usr/local/custom/bin", though note that variable expansion happens at load time, so
$PATH refers to the systemd manager’s initial path, not the user’s login path.
If your script requires multiple environment variables, list them on separate lines or combine them in a single
Environment= statement. For complex setups, consider using an
EnvironmentFile= to load variables from a dedicated configuration file, such as
/etc/default/my-service. This keeps the unit file clean and allows operators to tweak settings without editing the unit definition.
Handling Dependencies and Ordering
When using this workaround, you must ensure that the environment is set before the script runs. Since
Environment= applies to the entire service scope, it is available to all
ExecStart commands in the unit. However, if your script calls other binaries that depend on specific library paths, you may also need to set
LD_LIBRARY_PATH or use
DynamicUser= if applicable.
It is also important to check for conflicts with other systemd configurations. For instance, if you are using
systemctl set-environment globally, it might override your unit-specific settings. Always verify the effective environment by adding
Environment="DEBUG=true" and logging the output of
env in your script during testing. This helps confirm that your custom
PATH is being applied correctly.
For more details on variable usage in systemd, see our guide on
Understanding Variable Usage in systemd Unit Files.
Troubleshooting Common Issues
If your script still fails to find executables after applying this workaround, check the following:
1.
Syntax Errors: Ensure there are no spaces around the equals sign in
Environment=VAR=value. Spaces break the assignment.
2.
Case Sensitivity: Environment variable names are case-sensitive.
Path and
PATH are different.
3.
Quoting: If your path contains spaces, wrap the entire value in quotes, e.g.,
Environment="PATH='/usr/local/bin:/home/user/my dir/bin'".
4.
Logging: Check journalctl for errors related to the service activation. Look for messages about failed environment loading or permission denied errors.
By moving environment configuration to the service layer, you leverage systemd’s full capabilities while adhering to the constraints of the path monitoring subsystem. This pattern is widely used in production environments for reliability and maintainability.
Frequently Asked Questions
Can I use EnvironmentFile in a .path unit?
No, the
[Path] section does not support
EnvironmentFile=. You must place this directive in the corresponding
[Service] section of the triggered unit file.
Does this workaround affect performance?
There is negligible performance impact. The
.path unit remains lightweight, and the overhead of setting environment variables in the
.service unit is minimal compared to the actual task execution.
How do I debug environment issues in systemd?
Use
journalctl -u your-service.service -f to watch logs in real-time. Add a command like
exec env > /tmp/env.log as the first line of your script to dump the environment for inspection.
Can I use relative paths in Environment= directives?
It is best practice to use absolute paths in
Environment= directives. Relative paths can resolve unpredictably depending on the working directory, which may vary if
WorkingDirectory= is set.
What if my script needs root privileges?
Set
User=root and
Group=root in the
[Service] section. The environment variables defined with
Environment= will apply regardless of the user running the service, provided they are valid for that user context.