0

I am trying to run a simple script that checks the battery percentage and shows it through a notification (notify-send).
The script runs correctly if ran from terminal manually: ~/path-to-script/my_script.sh or sh ~/path-to-script/my_script.sh or even bash ~/path-to-my-script/my_script.sh.
Where correctly means that the notification is shown.

However when trying to run it through cron no notification appears. This is what crontab -e looks like:

*/1 * * * * /usr/bin/sh ~/path-to-my-script/my_script.sh

I have, also, set some environment variables in crontab with sudo vim /etc/crontab:

SHELL=/usr/bin/sh
PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin

And this is the log from sudo service cron status:

gen 28 17:35:01 my_user CRON[7863]: pam_unix(cron:session): session opened for user my_user(uid=1001) by (uid=0)
gen 28 17:35:01 my_user CRON[7864]: (my_user) CMD (/usr/bin/sh ~/path-to-my-script/my_script.sh)
gen 28 17:35:01 my_user CRON[7863]: (CRON) info (No MTA installed, discarding output)
gen 28 17:35:01 my_user CRON[7863]: pam_unix(cron:session): session closed for user my_user

I am running on Ubuntu 22.04 using i3 as window manager. What could be the cause of this issue?

Please ask if more info is needed.

2 Answers2

1

The modern and clean way to do this is to use the user's systemd timers. Missing the DBus environment variable is only one of the many reasons why cron is obsolete on modern Ubuntu Linux.

  1. Paste this in ~/.config/systemd/user/battery_notification.service:
[Unit]
Description=Sends notification about battery status

[Service]

%h means ~

ExecStart=%h/path-to-my-script/my_script.sh Type=oneshot

  1. Paste this in ~/.config/systemd/user/battery_notification.timer:
[Unit]
Description=Show battery notification every minute

If you want to limit it to a specific desktop environment,

you can change this line.

This mostly prevents unnecessary runs in SSH or after logging out,

and is another advantage over cron.

EDIT: Too bad i3 has a bug that breaks this: https://github.com/i3/i3/issues/5186

#Requisite=graphical-session.target #PartOf=graphical-session.target

[Install] #WantedBy=graphical-session.target WantedBy=dbus.service

[Timer] AccuracySec=1us

Initial delay

OnActiveSec=1s

Period

OnUnitActiveSec=1m

  1. Run the following:
systemctl --user daemon-reload
systemctl --user enable battery_notification.timer
systemctl --user start battery_notification.timer # Or reboot

You will see that the DBus environment variable, together will many other missing environment variables are set properly. The program is also now a child of one of your user processes, namely systemd --user not cron, so it is in the proper cgroup and other namespaces.

Another advantage is that it stops after you log out or if you don't log into your specified graphical environment. Useful commands might be systemctl --user list-timers to check the remaining time or systemctl --user disable battery_notification.timer && systemctl --user stop battery_notification.timer to stop it.

Daniel T
  • 5,339
0

As reported in my comment the solution turned out to be: prepending env DBUS_SESSION_BUS_ADDRESS=unix:path=/run/user/$(id -u)/bus to the command in crontab -e as follows:

*/1 * * * * env DBUS_SESSION_BUS_ADDRESS=unix:path=/run/user/$(id -u)/bus /usr/bin/sh ~/path-to-my-script/my_script.sh