如何区分systemd单元是手动执行还是由systemd timer触发?
systemctl Call Great question—this is a common need for tasks like backups where you want to adjust behavior based on whether the run was scheduled or on-demand. You're right that systemd timers don't pass unique environment variables to the service by default, but there are a few reliable ways to handle this directly within systemd's ecosystem.
Here are the most practical methods:
1. Check the Service's TriggeredBy Property in Your Script
When a systemd service is started by a timer, the service's metadata will list the timer as its trigger. You can query this directly in your backup script to determine the launch source.
Add this snippet to your backup script:
# Replace "my-backup.service" with your actual service name TRIGGER_SOURCE=$(systemctl show --property=TriggeredBy my-backup.service | cut -d'=' -f2) if [[ "$TRIGGER_SOURCE" == "my-backup.timer" ]]; then echo "Running scheduled backup (triggered by timer)" # Add timer-specific logic here (e.g., quiet mode, full backup) else echo "Running manual backup (initiated via systemctl)" # Add manual-specific logic here (e.g., user notifications, incremental backup) fi
This works because systemctl show --property=TriggeredBy returns the unit that started the service—empty or non-timer values mean a manual start.
2. Use ExecStartPre to Set a Trigger Environment Variable
You can embed the trigger check directly into your service unit file using ExecStartPre, which runs before your main backup command. This sets an environment variable your script can use without extra code in the script itself.
Modify your service unit (e.g., /etc/systemd/system/my-backup.service):
[Unit] Description=My Backup Service [Service] # Check if triggered by the corresponding timer and set an env var ExecStartPre=/bin/sh -c 'if systemctl show --property=TriggeredBy %n | grep -q "%N.timer"; then echo "BACKUP_TRIGGER=scheduled" > /run/systemd/service-%i.env; else echo "BACKUP_TRIGGER=manual" > /run/systemd/service-%i.env; fi' # Load the generated environment file EnvironmentFile=-/run/systemd/service-%i.env # Your actual backup command ExecStart=/path/to/your/backup/script.sh
In your backup script, you can now reference $BACKUP_TRIGGER to branch logic:
if [[ "$BACKUP_TRIGGER" == "scheduled" ]]; then # Scheduled backup logic else # Manual backup logic fi
The %n and %N are systemd specifiers: %n is the full service name (e.g., my-backup.service), and %N is the name without the .service suffix (so %N.timer becomes my-backup.timer).
Why Timer Environment Variables Don't Work
As you noticed, setting environment variables in the timer unit won't affect the service. That's because timers only send a "start service" signal to systemd—they don't pass runtime context to the service. The service's environment is defined exclusively by its own unit configuration (Environment, EnvironmentFile, etc.) and the systemd runtime.
Bonus: Post-Run Log Checking
If you need to verify the trigger source after the fact, use journalctl with verbose output to look for the _SYSTEMD_TIMER field:
journalctl -u my-backup.service -o verbose | grep "_SYSTEMD_TIMER"
If the output includes your timer's name, the run was scheduled; if not, it was manual.
内容的提问来源于stack exchange,提问作者Wheart

