Cannot autorun a bash script containing notify-send at the startup

autostartbash-scriptingcrontab

I'm using Linux Mint Cinnamon 19.
I've written a simple script

   #!/bin/bash
   #test
   notify-send "text" "other text" -i dialog-warning

to notify me when it's executed.
In order to run the script at the startup I've tried the following procedures. Both of them didn't work.

First using init.d directory

  1. Made a simple bash script prova.sh and made it bootable with chmod command.
  2. Copied to /etc/init.d/ directory.
  3. Made a soft link to /etc/rc0.d/ directory.

Second using crontab

  1. Executed the command crontab -e.
  2. Added the following lines to the file:
    @reboot /home/user/prova.sh
  3. Executed the command update-rc.d cron defaults

Any advice?

Best Answer

notify-send uses D-Bus.

Normally when you're logged in to your desktop and use notify-send, the variable DBUS_SESSION_BUS_ADDRESS is in your environment and points to the proper socket (e.g. in my Kubuntu the value of the variable is unix:path=/run/user/1000/bus where 1000 is my UID). The socket is created when you first log in.

For notify-send to work as expected, the following conditions must be met:

  1. The tool properly locates the socked via the DBUS_SESSION_BUS_ADDRESS environment variable. It seems if the variable is not set then the tool will try $XDG_RUNTIME_DIR/bus.
  2. The acquired socket exists and is accessible.
  3. The tool is run by the right user (D-Bus checks whether UIDs of the calling process and the session daemon are the same).
  4. There is another program running for the right user that receives messages and actually displays notifications.

Your script, when it was invoked from /etc/init.d/, run as root. I think there was no variable, no socket and no notifying program for root.

When the script was invoked from your personal crontab, it run under your user but the variables were not set.

One method to fix this is to add these lines to your script before notify-send:

DBUS_SESSION_BUS_ADDRESS="unix:path=/run/user/$(id -u)/bus"
export DBUS_SESSION_BUS_ADDRESS

(General note: use env | grep ^DBUS_SESSION_BUS_ADDRESS= to verify if your OS uses this pattern).

Then you want to run the script as your user and to be logged in when notify-send runs (so the socket exists) and to be logged in to your desktop (so your desktop environment receives and displays the notification). Sole notify-send (like in your example) will most certainly run before you log in; the message from it will be discarded.

But if the script does some real job that takes time, then notify-send at the end will make sense. Even in this case you may log in too late to receive the notification though.


A better way to know if your script has finished is to log to a file:

# in the script
log="$HOME/prova.status.log"
echo "PID $$ started: $(date)" >"$log"
# real task here
# ...
echo "finished: $(date)" >>"$log"

This will not work well if more than one instance runs at a time; but you run just one instance per reboot, so it should be fine. Use notify-send as a secondary, less reliable yet convenient channel. Regardless of how late you log in, you can always examine the file and know whether you have already missed the notification or it is yet to come.

Related Question