Gsettings with cron - linux

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.

Related

Get bash script to open terminal

In Windows when I double-click a Batch script, it will automatically open a terminal window and show me what's happening. If I were to double-click a bash script in Linux, a terminal window does not open to show me what is happening; it runs in the background. I have seen that one can use one script to launch another script in a new terminal window with x-terminal-emulator -e "./script.sh", but is there any bash command I can put into the same (one) script.sh so that it will open a terminal and show me what's happening (or if I need to answer y/n questions)?
You can do something similar to what Slax
developers do in their bootinst.sh:
#!/usr/bin/env sh
#
# If you see this file in a text editor instead of getting it executed,
# then it is missing executable permissions (chmod). You can try to set
# exec permissions for this file by using: chmod a+x bootinst.sh
#
# Scrolling down will reveal the actual code of this script.
#
# if we're running this from X, re-run the script in konsole or xterm
if [ "$DISPLAY" != "" ]; then
if [ "$1" != "--rex" -a "$2" != "--rex" ]; then
konsole --nofork -e /bin/sh $0 --rex 2>/dev/null || xterm -e /bin/sh $0 --rex 2>/dev/null || /bin/sh $0 --rex 2>/dev/null
exit
fi
fi
# put contents of your script here
echo hi
# do not close the terminal immediately, let user look at the results
echo "Press Enter..."
read junk
This script would run correctly both when started in graphical
environment and in tty. It tries to restart the script inside
konsole and xterm and but if it doesn't find neither of them it
will simply run in the background.

Run script in a new screen if true

I have a script where it will check if background_logging is true, if it is then I want the rest of the script to run in a new detached screen.
I have tried using this: exec screen -dmS "alt-logging" /bin/bash "$0";. This will sometimes create the screen, etc. but other times nothing will happen at all. When it does create a screen, it doesn't run the rest of the script file and when I try to resume the screen it says it's (Dead??).
Here is the entire script, I have added some comments to explain better what I want to do:
#!/bin/bash
# Configuration files
config='config.cfg'
source "$config"
# If this is true, run the rest of the script in a new screen.
# $background_logging comes from the configuration file declared above (config).
if [ $background_logging == "true" ]; then
exec screen -dmS "alt-logging" /bin/bash "$0";
fi
[ $# -eq 0 ] && { echo -e "\nERROR: You must specify an alt file!"; exit 1; }
# Logging script
y=0
while IFS='' read -r line || [[ -n "$line" ]]; do
cmd="screen -dmS alt$y bash -c 'exec $line;'"
eval $cmd
sleep $logging_speed
y=$(( $y + 1 ))
done < "$1"
Here are the contents of the configuration file:
# This is the speed at which alts will be logged, set to 0 for fast launch.
logging_speed=5
# This is to make a new screen in which the script will run.
background_logging=true
The purpose of this script is to loop through each line in a text file and execute the line as a command. It works perfectly fine when $background_logging is false so there are no issues with the while loop.
As described, it's not entirely possible. Specifically what is going on in your script: when you exec you replace your running script code with that of screen.
What you could do though is to start screen, figure out few details about it and redirect your console scripts in/output to it, but you won't be able to reparent your running script to the screen process as if started there. Something like for instance:
#!/bin/bash
# Use a temp file to pass cat's parent pid out of screen.
tempfile=$(tempfile)
screen -dmS 'alt-logging' /bin/bash -c "echo \$\$ > \"${tempfile}\" && /bin/cat"
# Wait to receive that information on the outside (it may not be available
# immediately).
while [[ -z "${child_cat_pid}" ]] ; do
child_cat_pid=$(cat "${tempfile}")
done
# point stdin/out/err of the current shell (rest of the script) to that cat
# child process
exec 0< /proc/${child_cat_pid}/fd/0
exec 1> /proc/${child_cat_pid}/fd/1
exec 2> /proc/${child_cat_pid}/fd/2
# Rest of the script
i=0
while true ; do
echo $((i++))
sleep 1
done
Far from perfect and rather messy. It could probably be helped by using a 3rd party tool like reptyr to grab console of the script from inside the screen. But cleaner/simpler yet would be to (when desired) start the code that should be executed in that screen session after it has been established.
That said. I'd actually suggest to take a step back and ask, what exactly is it that you're trying to achieve and why exactly would you like to run your script in screen. Are you planning to attach/detach to/from it? Because if running a long term process with a detached console is what you are after, nohup might be a bit simpler route to go.

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

How to set the wallpaper using cron

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

ssh & script problem

I am having a strange problem while doing ssh. I am not sure where the term Unmatched ` is coming from. What I need to do is run script that logs information of what I am doing on the terminal to text file. After ssh -
Sun Microsystems Inc. SunOS 5.8 Generic Patch October 2001
This is /etc/motd, last updated 3 Feb 2003.
To learn about the UCS system and other aspects of computing at UL-Lafayette
visit our home page http://helpdesk.louisiana.edu/ .
For more information about system use, contact the Help Desk, Stephens
Hall, Room 201, 482-5516 (x25516), during normal UL office hours; or send
e-mail to helpdesk#louisiana.edu.
ATTENTION:
Unsecure Telnet and FTP will be turned off soon.
Please make arrange to use ssh or sftp.
Putty(telnet) and WinSCP(ftp) would be a good replacement.
Unmatched `
d13.ucs.louisiana.edu% bash
bash-2.04$ script -a myInformation.txt
Script started, file is myInformation.txt
Unmatched `
d13.ucs.louisiana.edu%
When I tried to start the script with name myInformation.txt, you can see the message I am getting - Script started, file is myInformation.txt. But again I am getting that message Unmatched ` and is coming out of bash, as you can notice. What is the problem ? Any insights suggested would be very great.
Note: file with name myInformation.txt is being created but nothing goes in to it. As I have even tried running certain commands like ls and then exited the script with ctrl+d. But when I open the file, nothing is there.
.cshrc
`# #(#)cshrc 1.11 89/11/29 SMI
if ( `uname -s` == "Linux") then
# /etc/csh.{cshrc,login} set the csh and tcsh environments for Linux
# We just modify a few here:
set history=20 savehist=20
exit 0
endif
umask 027
# add here additional directories
set lpath = ()
set path = (~ ~/bin $lpath /usr/local/bin /usr/ccs/bin /usr/dt/bin /usr/openwin/bin /usr/bin /usr/sbin /usr/ucb .)
unset lpath
set noclobber
# Comment out the next line if you WANT core dumps (to debug via dbx,adb,gdb...)
limit coredumpsize 0
# An alternative to the above is to symlink ~/core to /dev/null ....
# Note that a core file can put you over quota, necessitating a command-line
# login [pick from the CDE Options menu] to be able to remove it.
if ( $?prompt == 0) exit
# Put here cmds suitable just for interactive c-shells
set history=20 savehist=20 time=10 autologout=28800
#set ignoreeof
set filec
set notify
#alias ls 'ls -F'
alias mail mailx
alias nissql /pkgs2/mysql/bin/mysql -h calvados.ucs.louisiana.edu -u cs4601d -p cs4601_d
.login
# #(#)local.login 1.5 98/10/03 SMI
if (`uname -s` == "Linux") then
exit 0
endif
if (! $?DT ) then
# Insert HERE and commands that are interactive, or alter the terminal
# characteristics. Thus, they will be bypassed if you start CDE and your
# .dtprofile invokes .login. Also remember /etc/.login is run first
# by non-CDE logins, and already sets some terminal characteristics.
# -- jpd#usl.edu
stty -istrip
endif
# environment variables
#setenv EXINIT 'set sh=/bin/csh sw=4 ai report=2'
#setenv MORE '-c'
#setenv PRINTER lw
setenv RNINIT '-I -e -m -S -i=11 -N -/ -h +hdate +hlines +hfrom -hdate-'
setenv LESS mQ
#setenv PRDEPT nnnn
setenv PAGER /usr/local/bin/less
#setenv EDITOR /usr/local/bin/emacs
setenv MANPATH /usr/local/man:/usr/local/perl/man:/usr/dt/man:/usr/openwin/man:/usr/man
#setenv AB2_DEFAULTSERVER http://pineau.ucs.louisiana.edu:8888/
setenv AB2_DEFAULTSERVER http://docs.sun.com:80/
setenv H_SPELL /dev/null
#
# if possible, start the windows system. Give user a chance to bail out
# To enable attempting openwin, set try_openwin=1 in the line below:
set try_openwin=0
if ( `tty` == "/dev/console" && $try_openwin) then
if ( "$TERM" == "sun" || "$TERM" == "sun-color" || "$TERM" == "AT386" ) then
if ( ${?OPENWINHOME} == 0 ) then
setenv OPENWINHOME /usr/openwin
endif
echo ""
echo -n "Starting OpenWindows in 5 seconds (type Control-C to interrupt)"
sleep 5
echo ""
$OPENWINHOME/bin/openwin
clear # get rid of annoying cursor rectangle
echo -n "Automatically logging out (type Control-C to interrupt)"
sleep 5
logout # logout after leaving windows system
endif
endif
unset try_openwin
The extra ` seems to be right there in the very beginning of your .cshrc.
...except of course if you are running bash as you say. What's the output of ps?

Resources