How to set the wallpaper using cron - linux

I have this script and it works:
#!/bin/bash
xfconf-query -c xfce4-desktop \
-p /backdrop/screen0/monitor0/workspace0/last-image \
-s /home/user/Pictures/wallpaper.png
But the cronie does not want to execute it (notify-send works good).
There is an error in the logs:
CMDOUT (Failed to init libxfconf: Using X11 for dbus-daemon autolaunch was disabled at compile time, set your DBUS_SESSION_BUS_ADDRESS instead.)
I tried to use export $(dbus-launch) in my .bashrc, but this did not solve the problem.

There are some issues using cron and accessing the X display/cookie file.
There is a file named "$machine_id-$display_number" where
$machine_id is a random number stored in /var/lib/dbus/machine-id
$display_number is the X Display number, which means the $DISPLAY (which is :$display_number or :$display_number.$screen_number).
This file (let's refer it as "dbus file"), is stored in ~/.dbus/session-bus
and contains information about DBUS_SESSION_BUS_ADDRESS and DBUS_SESSION_BUS_PID (it's a text file).
You will need to export those 2 variables from the file.
dbus_session_file=~/.dbus/session-bus/$(cat /var/lib/dbus/machine-id)-0
if [ -e "$dbus_session_file" ]; then
. "$dbus_session_file"
export DBUS_SESSION_BUS_ADDRESS DBUS_SESSION_BUS_PID
xconf-query ...
fi
NOTES:
I assume you are not logged in as root (and that your cron is under root privileges).
Beware that there's no guarantee that the user is still logged in. If he is logged out, the dbus daemon will be unavailable.
I wanted to explain what happens in the background. But there are easier ways to find the PID of a process in the desktop session, and obtain the dbus address from its environment
export $( < /proc/$pid/environ tr \0 \n | grep -E '^DBUS_SESSION_BUS_ADDRESS=')

I do it with feh through cronie on Arch as well
I'm using a one liner, which takes a random picture from a given folder and addresses it with DISPLAY:=0 to the current display
#!/bin/bash
file=$(find ~/Pictures/.wallpaper/ -type f | shuf -n1) && DISPLAY=:0 feh --bg-scale $file

in the bash script do this (so it can be successful in crontab):
export DBUS_SESSION_BUS_ADDRESS=unix:path=/run/user/$UID/bus
xfconf-query ...
from https://bbs.archlinux.org/viewtopic.php?pid=1706208#p1706208

Related

Mutt failing as cron job with 'Couldn't lock /sent'

I have a bash script which picks up files from /tmp and emails them to me. I run this script as root and it works perfectly but I am trying to get this automated with crontab.
Added the job to crontab, again running as root, and now I get 'Couldn't lock /sent'.
I managed to confirm it's using the file in /root by changing it's name in Muttrc and tried permission at 600 and 777.
(Also getting an error Segmentation fault, hoping that will go away if I fix the above.)
Anyone any ideas why Mutt is different as a cron job with the same user and the same file.
I simplified the script as follows and is doing exactly the same, works from root shell, but not in crontab.
error:-
Couldn't lock /sent
/data/mediators/email_file: line 5: 1666 Segmentation fault mutt $email -s "test" -i /tmp/test.txt < /dev/null
email_file script:-
#!/bin/bash
email=——#——.com
mutt $email -s "test" -i /tmp/test.txt < /dev/null
crontab:-
SHELL=/bin/bash
PATH=/sbin:/bin:/usr/sbin:/usr/bin
MAILTO=——#—-.com
HOME=/
54 02 * * * root /data/mediators/email_file
I also added printenv to the job and compared to a server where this runs OK. The difference is that the working system has USER=root, whereas the non-working one does not show this variable as being set.
The issue is combination of HOME=/ env variable in crontab and default mutt record configuration which defaults to ~/sent.
mutt stores sent emails in the record file. So choose whether you want to keep them (fix crontab's env var HOME or set mutt's record to meaningful value.
Add this option to mutt command in email_file If you want to set it:
-e 'set record=/root/sent'
or unset it with:
-e 'unset record'
You can find more in man pages muttrc(5)
record
Type: path
Default: “~/sent”
This specifies the file into which your outgoing messages should be appended. (This is meant as the primary method for saving a copy of your messages, but another way to do this is using the “my_hdr” command to create a “Bcc:” field with your email address in it.)
The value of $record is overridden by the $force_name and $save_name variables, and the “fcc-hook” command. Also see $copy and $

Can't get remote ssh stdout output in cron, but in my terminal it works

I run into an issue last week that drives me crazy. I wrote a BASH script which does a remote ssh connection to acamai and than performs a simple 'ls'. I want to redirect the 'ls' sdtout output to a given file.
While the script itself works like a charm when run manually, it does not while it runs via cron. The cronjob runs as root and each command works as expected expect the ssh command. My System is Gentoo Linux and cron is the old but gold vixie-cron.
To reduce the 200 LOC I put the basics herein which alone (as a single script) are enough to demonstrate the problem.
#!/bin/bash
PATH='/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/opt/bin'
#set -x
shopt -s lastpipe
exec 2>log.out
(ssh -i <path to key> -o HostKeyAlgorithms=+ssh-dss -o StrictHostKeyChecking=no <account#example.com> 'ls -r <path>') > '/root/listing.txt'
Even in -vvv debug mode of ssh I can see, that everything works...just except that I get no stdout output.
Than I tried something else that I found in another posting on the internet:
#!/bin/bash
PATH='/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/opt/bin'
#set -x
shopt -s lastpipe
exec 2>log.out
(ssh -T -i <path to key> -o HostKeyAlgorithms=+ssh-dss -o StrictHostKeyChecking=no <account#example.com> 'ls -r <path>' </dev/zero) > '/root/listing.txt'
Drawback here, I start a ssh session that I can't close and I guess its due to /dev/zero.
Another approach was to TEE Pipe the sub-shell of the ssh command...this worked for a short time ( and why not yet anymore ?!)
Now I'm clueless and need help. Cron has its PATH, uses BASH etc. Curious my boss did that with success with java (and he hates BASH...).
Any explanation and helpful tips are greatly welcome.
I have same issue, I make script for CRON and it gets output from remote SSH host.
If i run script manually - it works as should. But when CRON runs it - i get just a part of remote output.
I cant realise why its happening.
#!/bin/sh
pass=123
filelist=$(sshpass -p "$pass" ssh -q -tt -o StrictHostKeyChecking=no user#"10.10.10.10" "list")
filestring=$(echo "$filelist" | grep -Po "(\S+\s\S+\s+\d+\s\d{2}:\d{2}:\d{2}\s\d{4})\slist0\.lst")
filedate=${filestring% list0.lst}
echo $filedate
filestamp=$(date -d "$filedate" +"%s")
echo $filestamp
When i get echos in file via CRON - there are date from 0:00:00 - field with date (echo $filedate) is empty. But when i run manually - i get normal date with time...
It really bother me.
Help?
I found solution - add "-tt" to ssh command and all input goes to variable.
filelist=$(sshpass -p "$pass" ssh -q -tt -o StrictHostKeyChecking=no user#"10.10.10.10" "list")

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

How to run screen executing a command over ssh with tty

I tried many things today to have ssh start a screen session which executes a command. The goal is to run a command on a remote machine and to be able to see the output and to detach and reattach latter. I want to do it from within a script without any interaction except detaching the screen session to close. No satisfying solution so far.
ssh -t ${host} "\
source ~/.bashrc; \
echo \"done.\"; \
cd \"$exedir\"; \
if [ \$? -ne 0 ]; then \
echo \"could not cd into directory\"; \
exit 1; \
fi; \
echo \"executing remotexe.sh ...\"; \
screen -S "remotexe" -t "remotexe" -R "nice -n$prio ./remotexe.sh ${exeparams[#]}";"
Some of the problems I encounter are related to the strange ways to pass commands to screen/ssh/bash which interfere with arguments and options (I don't quite understand why they do not use -- to interpret whatever follows as commands with arguments). The above version almost works. The remaining difficulty is that commands in remotexe.sh (in particular make) obviously miss exports and definitions from .bashrc. This is why I tried to include the source ~/.bashrc. I tried to add similar commands or explicit exports to remotexe.sh but it behaves as if it was executed by /bin/sh. If I do a conventional ssh login I can immediately run the remotexe.sh script without error. I also tried adding shell -$SHELL to my .screenrc.
Where is the mistake in this solution? How can I correct it?
I haven't tested your code at all, and will not vouch for the sanity of this, but you definitely have a quoting error. Try:
ssh -t ${host} "
source ~/.bashrc;
echo done.;
cd \"$exedir\" || exit 1;
echo executing remotexe.sh ...;
screen -S remotexe -t remotexe -R nice -n$prio ./remotexe.sh ${exeparams[#]};"

Gsettings with cron

I wrote a bash script that changes the wallpaper (for GNOME3).
#!/bin/bash
# Wallpaper's directory.
dir="${HOME}/images/wallpapers/"
# Random wallpaper.
wallpaper=`find "${dir}" -type f | shuf -n1`
# Change wallpaper.
# http://bit.ly/HYEU9H
gsettings set org.gnome.desktop.background picture-options "spanned"
gsettings set org.gnome.desktop.background picture-uri "file://${wallpaper}"
Script executed in a terminal emulator (eg gnome-terminal) works great. During the execution by cron, or ttyX terminal getting the error:
** (process:26717): WARNING **: Command line `dbus-launch --autolaunch=d64a757758b286540cc0858400000603 --binary-syntax --close-stderr' exited with non-zero exit status 1: Autolaunch error: X11 initialization failed.\n
** (process:26717): WARNING **: Command line `dbus-launch --autolaunch=d64a757758b286540cc0858400000603 --binary-syntax --close-stderr' exited with non-zero exit status 1: Autolaunch error: X11 initialization failed.\n
** (process:26721): WARNING **: Command line `dbus-launch --autolaunch=d64a757758b286540cc0858400000603 --binary-syntax --close-stderr' exited with non-zero exit status 1: Autolaunch error: X11 initialization failed.\n
** (process:26721): WARNING **: Command line `dbus-launch --autolaunch=d64a757758b286540cc0858400000603 --binary-syntax --close-stderr' exited with non-zero exit status 1: Autolaunch error: X11 initialization failed.\n
Finally I managed how to solve this issue after many, many attempts.
Indeed, the problem occur because cron uses only a very restricted set of environment variables. And the only one environment variable that is responsible for running in the right way the script from the question when this is set as a cron job is DBUS_SESSION_BUS_ADDRESS, not DISPLAY or XAUTHORITY or GSETTINGS_BACKEND or something else. This fact was also pointed well in this answer.
But the problem in this answer is that there's no guarantee that the DBUS_SESSION_BUS_ADDRESS variable from that file from ~/.dbus/session-bus/ directory is updated to the current value from the current gnome session. To go over this problem a method would be to find the PID of a process in the current gnome session, and obtain the dbus address from its environment. We can do this as follow:
PID=$(pgrep gnome-session) # instead of 'gnome-session' it can be also used 'noutilus' or 'compiz' or the name of a process of a graphical program about that you are sure that is running after you log in the X session
export DBUS_SESSION_BUS_ADDRESS=$(grep -z DBUS_SESSION_BUS_ADDRESS /proc/$PID/environ|cut -d= -f2-)
That being said, the script should look like:
#!/bin/bash
# TODO: At night only dark wallpapers.
# Wallpaper's directory.
dir="${HOME}/images/wallpapers/"
# export DBUS_SESSION_BUS_ADDRESS environment variable
PID=$(pgrep gnome-session)
export DBUS_SESSION_BUS_ADDRESS=$(grep -z DBUS_SESSION_BUS_ADDRESS /proc/$PID/environ|cut -d= -f2-)
# Random wallpaper.
wallpaper=`find "${dir}" -type f | shuf -n1`
# Change wallpaper.
# http://bit.ly/HYEU9H
gsettings set org.gnome.desktop.background picture-options "spanned"
gsettings set org.gnome.desktop.background picture-uri "file://${wallpaper}"
I found some solutions. When you export a variable DBUS_SESSION_BUS_ADDRESS contained in the file ~/.dbus/session-bus/*, dbus-launch does not tell more about the error. However, instead of wallpaper there are artefacts.
Added code:
sessionfile=`find "${HOME}/.dbus/session-bus/" -type f`
export `grep "DBUS_SESSION_BUS_ADDRESS" "${sessionfile}" | sed '/^#/d'`
Now the script looks like this:
#!/bin/bash
# TODO: At night only dark wallpapers.
# Wallpaper's directory.
dir="${HOME}/images/wallpapers/"
# Weird, but necessary thing to run with cron.
sessionfile=`find "${HOME}/.dbus/session-bus/" -type f`
export `grep "DBUS_SESSION_BUS_ADDRESS" "${sessionfile}" | sed '/^#/d'`
# Random wallpaper.
wallpaper=`find "${dir}" -type f | shuf -n1`
# Change wallpaper.
# https://superuser.com/questions/298050/periodically-changing-wallpaper-under-gnome-3/298182#298182
gsettings set org.gnome.desktop.background picture-options "spanned"
gsettings set org.gnome.desktop.background picture-uri "file://${wallpaper}"
Tried this and it worked great for me:
dbus-launch --exit-with-session gsettings set schema key value
Or from root cron:
sudo -u user dbus-launch --exit-with-session gsettings set schema key value
Credit: http://php.mandelson.org/wp2/?p=565
add export DISPLAY=:0 && export XAUTHORITY=/home/username/.Xauthority , where username is your ubuntu username. It should fix the X11 authorisation error.
To change your wallpaper through cron, just do this directly in your crontab :
Execute crontab -e
Add lines like this :
30 09 * * * DISPLAY=:0 GSETTINGS_BACKEND=dconf /usr/bin/gsettings set org.gnome.desktop.background picture-uri file:////home/elison/Pictures/morning.jpg
00 12 * * * DISPLAY=:0 GSETTINGS_BACKEND=dconf /usr/bin/gsettings set org.gnome.desktop.background picture-uri file:////home/elison/Pictures/noon.jpg
Also see this solution that work for me:
https://unix.stackexchange.com/questions/111188/using-notify-send-with-cron#answer-111190
:
You need to set the DBUS_SESSION_BUS_ADDRESS variable. By default cron does not have access to the variable. To remedy this put the following script somewhere and call it when the user logs in, for example using awesome and the run_once function mentioned on the wiki. Any method will do, since it does not harm if the function is called more often than required.
#!/bin/sh
touch $HOME/.dbus/Xdbus
chmod 600 $HOME/.dbus/Xdbus
env | grep DBUS_SESSION_BUS_ADDRESS > $HOME/.dbus/Xdbus
echo 'export DBUS_SESSION_BUS_ADDRESS' >> $HOME/.dbus/Xdbus
exit 0
This creates a file containing the required Dbus evironment variable. Then in the script called by cron you import the variable by sourcing the script:
if [ -r "$HOME/.dbus/Xdbus" ]; then
. "$HOME/.dbus/Xdbus"
fi
And finally the ugly, no cron at all (darn it)! Using other methods the changes get set in gconf, but the image does not change. Maybe it is because I am running Deepin's DDE (dde makes use of the same path, different key). Ugly for the rescue: A final attempt to make this saga work.
With this script the wallpaper is changed every 420 seconds (7 minutes) in an endless loop picking a random wallpaper from one of 4 sets (or directories), acordingly to the time of the day or night.
I've created a .desktop file and added this .desktop file to the "~/.config/autostart". I've also created another pair script/desktop without the loop to be on my dock, so I can click on it and change it on fly too.
Set the ugly up: save the script as wallpaperd somewhere and make it executable:
chmod +x wallpaperd
Now create a folder called Wallpaper inside the Pictures directory. Inside this Wallpaper folder create 4 more folders with the names afternoon, duskdawn, morning and night. Put the image files you wish in those 4 directories.
mkdir -p ~/Pictures/Wallpaper/morning
mkdir ~/Pictures/Wallpaper/afternoon
mkdir ~/Pictures/Wallpaper/night
mkdir ~/Pictures/Wallpaper/duskdawn
wallpaperd
#!/bin/bash
for (( ; ; ))
do
me="MyUser" # Change me!
morning="morning"
afternoon="afternoon"
dawn="duskdawn"
night="night"
dusk="duskdawn"
now="morning"
hour=$(date +%R | sed 's/\:.*//')
if [ "$hour" -ge 7 ] && [ "$hour" -lt 12 ]
then
now="morning"
elif [ "$hour" -ge 12 ] && [ "$hour" -lt 17 ]
then
now="afternoon"
elif [ "$hour" -ge 17 ] && [ "$hour" -lt 18 ]
then
now="duskdawn"
elif [ "$hour" -ge 18 ] && [ "$hour" -le 23 ]
then
now="night"
elif [ "$hour" -ge 0 ] && [ "$hour" -lt 6 ]
then
now="night"
elif [ "$hour" -ge 6 ] && [ "$hour" -lt 7 ]
then
now="duskdawn"
fi
imgPath="/home/$me/Pictures/Wallpaper/$now/"
imgFile=$(ls -1 $imgPath | shuf -n 1 | awk '{print $NF}')
export bgNow=""$imgPath$imgFile""
# Deepin desktop
/usr/bin/gsettings set com.deepin.wrap.gnome.desktop.background picture-uri "$bgNow"
# Gnome desktop
#/usr/bin/gsettings set org.gnome.desktop.background picture-uri "$bgNow"
sleep 420
done
Set the proper gsettings command for your desktop in script!
wallyd.desktop
** Autostart Path: /home/YOUR_USER/.config/autostart/wallyd.desktop**
[Desktop Entry]
Categories=System;
Comment=Change Wallpapers Agent
Exec=/home/$USER/Bin/wallpaperd
Icon=computer
Name=Wally Daemon
NoDisplay=false
Terminal=false
Type=Application
Edit the script's path to match the path where you saved the script.
No loop
To create a desktop icon without the loop, only to change the wally and quit do this:
Save the script as wallpaper (without the d at the end) and remove these lines:
for (( ; ; ))
do
done
Use the template above to create another .desktop file for this non looped wallpaper script. Change the Name and the Exec path for the non looped script.
Save this .desktop here:
/usr/share/applications/wally.desktop
Drag it to your taskbar or dock. Click it and it will change the wallpaper on the fly.
When setting the DBUS_SESSION_BUS_ADDRESS environment variable, the PID=$(pgrep gnome-session) command may return multiple values in certain cases. This can cause issues when setting the environment variable using the grep command.
To address this issue, you can use the pgrep command with the -t option to limit the search to a specific terminal. In this case, you can use PID=$(pgrep -t tty2 gnome-session) to limit the search to the second terminal (tty2) and ensure that only one PID is returned.
Therefore, for Ubuntu 22.04, you can modify the command to:
PID=$(pgrep -t tty2 gnome-session)
export DBUS_SESSION_BUS_ADDRESS=$(grep -z DBUS_SESSION_BUS_ADDRESS /proc/$PID/environ|cut -d= -f2-)
This should allow you to set the DBUS_SESSION_BUS_ADDRESS environment variable correctly, even when multiple gnome-session processes are running.
Thanks to Ray Foss for providing this solution in the comments to the original answer.

Resources