Cron with notify-send - linux

I need to show a notification from a cron job. My crontab is something like:
$ crontab -l
# m h dom mon dow command
* * * * * Display=:0.0 /usr/bin/notify-send Hey "How are you"
I checked /var/log/syslog and the command is actually executed every minute but it doesn't pop up the notification.
Can anybody help me understand why?

I use i3 on Ubuntu 18.04. My way to solve this is:
* * * * * XDG_RUNTIME_DIR=/run/user/$(id -u) notify-send Hey "this is dog!"
Edit 2020: I still use it on Ubuntu 20.04.

I found the answer:
$ crontab -l
# m h dom mon dow command
* * * * * export DISPLAY=:0.0 && export XAUTHORITY=/home/ravi/.Xauthority && sudo -u ravi /usr/bin/notify-send Hey "How are you"

In Ubuntu 14.04 exporting the display did not work for me. Below is a cron script I'm using to shutdown a virtual machine when a laptop's battery state becomes too low. The line setting DBUS_SESSION_BUS_ADDRESS is the modification that finally got the warnings working correctly.
#!/bin/bash
# if virtual machine is running, monitor power consumption
if pgrep -x vmware-vmx; then
bat_path="/sys/class/power_supply/BAT0/"
if [ -e "$bat_path" ]; then
bat_status=$(cat $bat_path/status)
if [ "$bat_status" == "Discharging" ]; then
bat_current=$(cat $bat_path/capacity)
# halt vm if critical; notify if low
if [ "$bat_current" -lt 10 ]; then
/path/to/vm/shutdown/script
echo "$( date +%Y.%m.%d_%T )" >> "/home/user/Desktop/VM Halt Low Battery"
elif [ "$bat_current" -lt 15 ]; then
eval "export $(egrep -z DBUS_SESSION_BUS_ADDRESS /proc/$(pgrep -u $LOGNAME gnome-session)/environ)";
notify-send -i "/usr/share/icons/ubuntu-mono-light/status/24/battery-caution.svg" "Virtual machine will halt when battery falls below 10% charge."
fi
fi
fi
fi
exit 0
The relevant line is here:
eval "export $(egrep -z DBUS_SESSION_BUS_ADDRESS /proc/$(pgrep -u $LOGNAME gnome-session)/environ)";
I found the solution here: https://askubuntu.com/a/346580/255814

Only this works for me (Xubuntu)
eval "export $(egrep -z DBUS_SESSION_BUS_ADDRESS /proc/$(pgrep -u $LOGNAME xfce4-session)/environ)"; notify-send "hello world"
If you are in gnome enviroment, you need change xfce4-session to gnome-session
refer: https://askubuntu.com/questions/298608/notify-send-doesnt-work-from-crontab

add DBUS_SESSION_BUS_ADDRESS :
* * * * * DISPLAY=:0 DBUS_SESSION_BUS_ADDRESS=unix:path=/run/user/1000/bus /usr/bin/notify-send 'helloworld..' 'msg...'

Work for me on fedora 22:
Put this line in the .sh script before notify-send get called:
eval "export $(egrep -z DBUS_SESSION_BUS_ADDRESS /proc/$(pgrep -u $LOGNAME gnome-session)/environ)"

On recent Ubuntu versions, the following should work.
#notify_me.sh, can be placed e.g. in your home directory
#!/bin/bash
eval "export $(egrep -z DBUS_SESSION_BUS_ADDRESS /proc/$(pgrep -u $LOGNAME gnome-session)/environ)";
# the actual notification
DISPLAY=:0 notify-send "Notify me!"
Then you add a line to your user's cronjobs via crontab as usual.

Simple and reduced answer:
01 * * * * export DISPLAY=:0.0 && notify-send Hey "How are you"
If you need Xauthority permission, here's a generalizable form using the $LOGNAME variable
01 * * * * export DISPLAY=:0.0 && && export XAUTHORITY=/home/$LOGNAME/.Xauthority notify-send Hey "How are you"
As pointed out by #tripleee, there's no real need for sudo here

I created a /usr/bin script that uses the DISPLAY-:0.0 technique http://pastebin.com/h11p2HtN
It doesn't take XAUTHORITY into account. I'll have to investigate that further.

Similar to nmax above, I also solved the issue by setting DBUS_SESSION_BUS_ADDRESS environment variable.
However, I am using a combination of Linux Mint 19 (xfce4) and XMonad and for some reason, I don't have the process xfce4-session running. Instead, I found that xfce4-terminal is (usually) running, which resulted in the following line in the beginning of my script:
eval "export $(egrep -z DBUS_SESSION_BUS_ADDRESS /proc/$(pgrep -u $LOGNAME xfce4-terminal)/environ)"
This resolved the issue for me.

If you are having issue that your notify-send script is working fine locally but it is not working with cron jobs then use this command. and replace "saurav" with your username.
sudo -u saurav DISPLAY=:0 DBUS_SESSION_BUS_ADDRESS=unix:path=/run/user/1000/bus notify-send "Your message goes here"

In my case, the issue was with using root user with notify-send. I realized this when I saw that sudo notify-send didn't work on the terminal but just notify-send (i.e. with current user) did.
So instead of editing the usual /etc/crontab which is used by root, I had a custom cron script created for myusername. Please check my whole answer here.

May be you can try:
* * * * * env DISPLAY=:0.0 sudo -u ravi /usr/bin/notify-send Hey "How are you"

Try this when you call notify-send in your script:
echo "PASSWORD" | sudo -u USER notify-send "your alert message"

Related

Why doesn't $(which node) work inside a cron job executing a BASH shell?

According to this answer the reason cron doesn't have access to environment variables normally associated with a BASH terminal is because it doesn't source the users .bashrc file.
I have a script which does source my .bashrc file but it still fails to find my currently in use version of Node (meaning I need to list the full directory and change it with every update!).
Script:
#!/bin/bash
source $HOME/.bashrc # <-- even after sourcing .bashrc, '$(which node)' returns nothing
NODE="$(which node)" # <-- output is blank in cron job
PROCESS="/home/grayedfox/.nvm/versions/node/v8.9.4/bin/node /home/grayedfox/github/blockscrape/main.js"
LOGFILE="/tmp/log.out"
export BLOCKSCRAPECLI="/opt/litecoin-0.14.2/bin/litecoin-cli"
if pgrep -f "$PROCESS" > /dev/null; then
echo "Blockscrape is doing it's thing - moving on..." >> $LOGFILE
else
echo "Blockscrape not running! Starting again..." >> $LOGFILE
echo "Process: $PROCESS" >> $LOGFILE
echo "Node: $NODE" >> $LOGFILE # <-- outputs only 'Node: ' in log file
$PROCESS >> $LOGFILE
fi
Crontab:
# make default shell BASH
SHELL=/bin/bash
# reboots litecoin daemon if it dies
#reboot /opt/litecoin-0.14.2/bin/litecoind
# check every minute to see if block scrape running and restart it if not
* * * * * /home/grayedfox/github/blockscrape/restartBlockscrape.sh
I can confirm that node (and doing "which node") works fine in my terminal.
Thanks for the help!
As discussed in this answer - thethis answer problem was that in Ubuntu 16.04 (and many prior versions) the standard .bashrc file quits if it's not being run interactively.
Commenting out the below code from my bash file fixed it:
# If not running interactively, don't do anything
case $- in
*i*) ;;
*) return;;
esac

Cron not executing the shell script + Linux [duplicate]

I have a script that checks if the PPTP VPN is running, and if not it reconnects the PPTP VPN. When I run the script manually it executes fine, but when I make a cron job, it's not running.
* * * * * /bin/bash /var/scripts/vpn-check.sh
Here is the script:
#!/bin/sh
/bin/ping -c3 192.168.17.27 > /tmp/pingreport
result=`grep "0 received" /tmp/pingreport`
truncresult="`echo "$result" | sed 's/^\(.................................\).*$$'`"
if [[ $truncresult == "3 packets transmitted, 0 received" ]]; then
/usr/sbin/pppd call home
fi
finally i found a solution ... instead of entering the cronjob with
crontab -e
i needed to edit the crontab file directly
nano /etc/crontab
adding e.g. something like
*/5 * * * * root /bin/bash /var/scripts/vpn-check.sh
and its fine now!
Thank you all for your help ... hope my solution will help other people as well.
After a long time getting errors, I just did this:
SHELL=/bin/bash
PATH=/bin:/sbin:/usr/bin:/usr/sbin
* * * * * /bin/bash /home/joaovitordeon/Documentos/test.sh
Where test.sh contains:
#!/bin/bash
/usr/bin/python3 /home/joaovitordeon/Documentos/test.py;
In my case, the issue was that the script wasn't marked as executable. To make sure it is, run the following command:
chmod +x your_script.sh
If you're positive the script runs outside of cron, execute
printf "SHELL=$SHELL\nPATH=$PATH\n* * * * * /bin/bash /var/scripts/vpn-check.sh\n"
Do crontab -e for whichever crontab you're using and replace it with output of the above command. This should mirror most of your environment in case there is some missing path issue or something else. Also check logs for any errors it's getting.
Though it definitly looks like the script has an error or you messed something up when copying it here
sed: -e expression #1, char 44: unterminated `s' command
./bad.sh: 5: ./bad.sh: [[: not found
Simple alternate script
#!/bin/bash
if [[ $(ping -c3 192.168.17.27) == *"0 received"* ]]; then
/usr/sbin/pppd call home
fi
Your script can be corrected and simplified like this:
#!/bin/sh
log=/tmp/vpn-check.log
{ date; ping -c3 192.168.17.27; } > $log
if grep -q '0 received' $log; then
/usr/sbin/pppd call home >>$log 2>&1
fi
Through our discussion in comments we confirmed that the script itself works, but pppd doesn't, when running from cron. This is because something must be different in an interactive shell like your terminal window, and in cron. This kind of problem is very common by the way.
The first thing to do is try to remember what configuration is necessary for pppd. I don't use it so I don't know. Maybe you need to set some environment variables? In which case most probably you set something in a startup file, like .bashrc, which is usually not used in a non-interactive shell, and would explain why pppd doesn't work.
The second thing is to check the logs of pppd. If you cannot find the logs easily, look into its man page, and it's configuration files, and try to find the logs, or how to make it log. Based on the logs, you should be able to find what is missing when running in cron, and resolve your problem.
Was having a similar problem that was resolved when a sh was put before the command in crontab
This did not work :
#reboot ~myhome/mycommand >/tmp/logfile 2>&1
This did :
#reboot sh ~myhome/mycommand >/tmp/logfile 2>&1
my case:
crontab -e
then adding the line:
* * * * * ( cd /directory/of/script/ && /bin/sh /directory/of/script/scriptItself.sh )
in fact, if I added "root" as per the user, it thought "root" was a command, and it didn't work.
As a complement of other's answers, didn't you forget the username in your crontab script ?
Try this :
* * * * * root /bin/bash /var/scripts/vpn-check.sh
EDIT
Here is a patch of your code
#!/bin/sh
/bin/ping -c3 192.168.17.27 > /tmp/pingreport
result=`grep "0 received" /tmp/pingreport`
truncresult=`echo "$result" | /bin/sed 's/^\(.................................\).*$/\1/'`
if [[ $truncresult == "3 packets transmitted, 0 received" ]]; then
/usr/sbin/pppd call home
fi
In my case, it could be solved by using this:
* * * * * root ( cd /directory/of/script/ && /directory/of/script/scriptItself.sh )
I used some ./folder/-references in the script, which didn't work.
The problem statement is script is getting executed when run manually in the shell but when run through cron, it gives "java: command not found" error -
Please try below 2 options and it should fix the issue -
Ensure the script is executable .If it's not, execute below -
chmod a+x your_script_name.sh
The cron job doesn’t run with the same user with which you are executing the script manually - so it doesn't have access to the same $PATH variable as your user which means it can't locate the Java executable to execute the commands in the script. We should first fetch the value of PATH variable as below and then set it(export) in the script -
echo $PATH can be used to fetch the value of PATH variable.
and your script can be modified as below - Please see second line starting with export
#!/bin/sh
export PATH=<provide the value of echo $PATH>
/bin/ping -c3 192.168.17.27 > /tmp/pingreport
result=`grep "0 received" /tmp/pingreport`
truncresult="`echo "$result" | sed 's/^\(.................................\).*$$'`"
if [[ $truncresult == "3 packets transmitted, 0 received" ]]; then
/usr/sbin/pppd call home
fi
First of all, check if cron service is running. You know the first question of the IT helpdesk: "Is the PC plugged in?".
For me, this was happening because the cronjob was executing from /root directory but my shell script (a script to pull the latest code from GitHub and run the tests) were in a different directory. So, I had to edit my script to have a cd to my scripts folder. My debug steps were
Verified that my script run independent of cron job
Checked /var/log/cron to see if the cron jobs are running. Verified that the job is running at the intended time
Added an echo command to the script to log the start and end times to a file. Verified that those were getting logged but not the actual commands
Logged the result of pwd to the same file and saw that the commands were getting executed from /root
Tried adding a cd to my script directory as the first line in the script. When the cron job kicked off this time, the script got executed just like in step 1.
it was timezone in my case. I scheduled cron with my local time but server has different timezone and it does not run at all. so make sure your server has same time by date cmd
first run command env > env.tmp
then run cat env.tmp
copy PATH=.................. Full line and paste into crontab -e, line before your cronjobs.
try this
/home/your site folder name/public_html/gistfile1.sh
set cron path like above

vncserver bash script error in ubuntu 14.04.4 LTS

I use Ubuntu 14.04.4 LTS and installed vnc4server.
The basic script starting vncdesktops is under /etc/init.d/vncserver which is a bash script. This works fine for all users specified in /etc/vncserver/vncservers.conf with their arguments. But when a user is using csh instead of bash, the vncserver command doesn't work because of a syntax error in the vncserver script. The error occurs in the start() function which I show here.
start() {
. /lib/lsb/init-functions
REQ_USER=$2
echo -n $"Starting $prog: "
ulimit -S -c 0 >/dev/null 2>&1
RETVAL=0
for display in ${VNCSERVERS}
do
export USER="${display##*:}"
if test -z "${REQ_USER}" -o "${REQ_USER}" == ${USER} ; then
echo -n "${display} "
unset BASH_ENV ENV
DISP="${display%%:*}"
export VNCUSERARGS="${VNCSERVERARGS[${DISP}]}"
su ${USER} -c "cd ~${USER} && [ -f .vnc/passwd ] && vncserver :${DISP} ${VNCUSERARGS}"
fi
done
}
When I give the command 'sudo service vncserver restart' the vncserver script runs and give me this error for a user using csh.
Starting VNC server: 8:test1 [: No match.
user 'test1' is using csh and its display number is 8. I can see this error is coming from the line
su ${USER} -c "cd ~${USER} && [ -f .vnc/passwd ] && vncserver :${DISP} ${VNCUSERARGS}"
and I understand what it's doing but I don't know why the bracket condition is giving me this error and that only for a user using csh.
Can anyone give me a clue?
I don't know exactly why, but I found my /bin/csh was linked as below.
/bin/csh -> /etc/alternatives/csh
So I installed tcsh (apt-get install tcsh) and made the link like this.
/bin/csh -> /bin/tcsh
Then the problem is gone!
The su command and the command executed by -c option is being processed in the su'ed user's shell which was /etc/alternatives/csh which probably could not handle the [ -f ] condition. and I gues the /etc/alternatives/csh is a kind of default csh linked to when there is no real full fledged csh(like tcsh).

Using notify-send with cron

I've been trying to use notify-send with cron. I've checked out tons of answers given on stackoverflow and other forums. But I don't see the notify-send popup appearing. I'm currently running Ubuntu 13.10. I've been able to get this to work earlier (about 3 months ago when I had Ubuntu 11.10) but I don't remember how and I don't see what I'm doing wrong here.
My current crontab looks like:
*/1 * * * * export DISPLAY=:0.0 && export XAUTHORITY=/home/harold/.Xauthority && /usr/bin/notify-send "$(date)"
I've tried many solutions given online including using sudo -u harold right before /usr/bin/notify-send .... I've also tried using export DISPLAY=:0 instead of =:0.0. The popup still doesn't appear.
I've also tried to create a script. The cron job to run the script looks like:
*/1 * * * * cd /home/harold/bin && ./notify-send-test.sh
And my script (notify-send-test.sh) looks like:
#!/bin/bash
#export DISPLAY=:0
#export XAUTHORITY=/home/harold/.Xauthority
/usr/bin/notify-send "$(date)"
echo "trying to notify at $(date)" >> /home/harold/bin/cronlog.txt
I've tried using the commented lines and not using them. None of the combinations seem to work. I've also tried using export DISPLAY=0.0.
I do get the expected output in the cronlog.txt file every minute. This means that my script is being executed but the notify-send is not.
I would like to know what I am doing wrong. Happy to provide any more information that may be of use.
Secondary question:
There was also something about cron not being able to use certain environment variables. I don't get what that meant and how it affects the way I use cron. It would be nice if someone could explain this.
To add to Sakthi's answer.
You can get the DBUS_SESSIONBUS_ADDRESS withouth using nautilus (or gnome or whatever) by typing dbus-launch (see this answer)
So to the script would simply be:
#!/bin/bash
export $(dbus-launch)
/usr/bin/notify-send "$(date)"
If that doesn't work, you could try setting it hard-coded to your user ID:
#!/bin/bash
userid=$(id -u)
DBUS_SESSION_BUS_ADDRESS="unix:path=/run/user/$userid/bus"
export DBUS_SESSION_BUS_ADDRESS
/usr/bin/notify-send "$(date)"
You can add echo $(env | grep DBUS_SESSION_BUS_ADDRESS) in the script to check what the env variable is when the script is executed.
The DBUS_SESSION_BUS_ADDRESS env variable will not be set in cron daemon. Setting this value will fix your issue. Add the following changes to your .sh file and call it from crontab.
notify-send-test.sh
#!/bin/bash
username=$(/usr/bin/whoami)
pid=$(pgrep -u $username nautilus)
dbus=$(grep -z DBUS_SESSION_BUS_ADDRESS /proc/$pid/environ | sed 's/DBUS_SESSION_BUS_ADDRESS=//' )
export DBUS_SESSION_BUS_ADDRESS=$dbus
/usr/bin/notify-send "$(date)"
Crontab
*/1 * * * * /home/harold/bin/notify-send-test.sh

Script produces different result when executed by Bash than by cron

Please consider following crontab (root):
SHELL=/bin/bash
...
...
0 */3 * * * /var/maintenance/raid.sh
And the bash script /var/maintenance/raid.sh:
#!/bin/bash
echo -n "Checking /dev/md0... "
if ! [ $(mdadm --detail /dev/md0 | grep -c "active sync") -eq 2 ]; then
mdadm --detail /dev/md0 | mail -s "Raid problem /dev/md0" "my#email.com";
echo "ERROR"
else
echo "ALL OK"
fi;
#-------------------------------------------------------
echo -n "Checking /dev/md1... "
...
And this is what happen when...
...executed from shell prompt (bash):
Mail with mdadm --detail /dev/md0 output is sent to my email (proper behaviour)
...executed by cron:
Blank mail is sent to my email (subject is there, but there is no message)
Why such difference and how to fix it?
As indicated in the comments, do use full paths on crontab scripts, because crontab does have different environment variables than the normal user (root in this case).
In your case, instead of mdadm, /sbin/mdadm makes it.
How to get the full path of a command? Using the command command -v:
$ command -v rm
/bin/rm
cron tasks run in a shell that is started without your login scripts being run, which set up paths, environment variables etc.
When building cron tasks, prefer things like absolute paths and explicit options etc
Before running your script as a cron job, you can test it with no environment variables using env -i
env -i /var/maintenance/raid.sh

Resources