Currently trying to set up a cron job with a python script that I have git cloned from here. The hierarchy to reach my script can be described as below:

                                    /home
                                      |
                                      |
                            /Daily-Reddit-Wallpaper
                                      |
                                      |
                         change_wallpaper_reddit.py

Now this works when I use the command, python change_wallpaper_reddit.py --time new inside the Daily_Reddit_Wallpapers folder. However, when I try the command, * * * * * python ./change_wallpaper_reddit.py --time new, I get the error:

change_wallpaper_reddit.py: command not found

When I try to invoke * * * * * python ~/Daily-Reddit-Wallpaper/change_wallpaper_reddit.py, I get:

usage: anaconda [-h] [--show-traceback] [--hide-traceback] [-v] [-q] [--color]
                [--no-color] [-V] [-t TOKEN] [-s SITE]
                ...
anaconda: error: argument : invalid choice: 'Daily-Reddit-Wallpaper' (choose from 'auth', u'label', u'channel', 'config', u'copy', u'download', 'groups', u'login', 'logout', u'notebook', 'package', 'remove', 'search', 'show', u'upload', u'whoami')

I do not understand why this happens.


Please be aware the a cronjab executes in a shell that has a limited environment setup. By that I mean that when you open a terminal and enter env you will see a lot of environment variables; one of the most important ones is PATH. The cron job does not login so to speak, thus .profile files are not executed. So in your script you must make sure to set or complement environment variables like PATH.
Also, a cron entry should not use the ~ but put the full path.

In my system I created a small script to list the environment variables that are set when the script is started in cron. As you see a lot less than when in a terminal:

HOME=/home/willem
LANG=en_US.UTF-8
LC_ADDRESS=nl_NL.UTF-8
LC_IDENTIFICATION=nl_NL.UTF-8
LC_MEASUREMENT=nl_NL.UTF-8
LC_MONETARY=nl_NL.UTF-8
LC_NAME=nl_NL.UTF-8
LC_NUMERIC=nl_NL.UTF-8
LC_PAPER=nl_NL.UTF-8
LC_TELEPHONE=nl_NL.UTF-8
LC_TIME=nl_NL.UTF-8
LOGNAME=willem
PATH=/usr/bin:/bin
PWD=/home/willem
SHELL=/bin/sh
SHLVL=1
_=/usr/bin/env

Proper scripts start with a shebang expression, some text explaining what the script will do (you might forget after a few months) and then setting environment variables. A small example (NB willem is my user name:

#!/bin/bash    # Script is created and tested for Bash.
# Example script Hello, runs outside a terminal so PATH is minimal.
# We must set env vars.
# Note I do not use "export PATH=$PATH:..." etc, because I want my progs
# directory to be found first.
export MYHOME=/home/willem
export MYLOGS=$MYHOME/logs
export MYPROGS=$MYHOME/prog
export PATH=$MYPROGS:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/snap/bin
#
# The main code of the script:
#
echo "Hello: started" > $MYLOGS/Hello.log
goodDay >> $MYLOGS/Hello.log   # goodDay is also in $MYPROGS
...
...
#EOF

To put the script in cron, enter crontab -e:
You are in vi so go to end of file and add:
* * * * * /home/willem/prog/Hello

Close and save, and view your crontab entry/entries: crontab -l


The problem is that, the script isn't designed to work with Cron. It uses few environment variables, which are not accessible from Cron and they are different, depending on the current user's desktop environment. This is the reason on its page to be described another way for running on startup. But it is possible to set values of these variables while the CronJob is running.

For example, when it is the default Ubuntu's desktop environment, the search key words should become: 'gsettings' and 'cron', then our search will lead us to wired topics as: Background not changing using gsettings from cron, where we could find additional explanations as:

If you run the script from your own environment (e.g. from a terminal window or from Startup Applications), a number of environment variables will be set. cron however runs your script with a limited set of environment variables.

To edit gsettings successfully from cron, you need to set the DBUS_SESSION_BUS_ADDRESS environment variable. You can do that by adding two lines to your script, as described here...


Run: Daily-Reddit-Wallpaper through Cron via Startup script

Here we will create a startup script, which shall set the necessary environment variables depending of the chosen (by an argument) desktop environment.

1. First cloned Daily-Reddit-Wallpaper and also install the dependencies:

cd ~
git clone https://github.com/ssimunic/Daily-Reddit-Wallpaper.git
cd ~/Daily-Reddit-Wallpaper
sudo apt-get install python-pip
pip install -r requirements.txt

2. Create the script file - change_wallpaper_reddit.sh:

cd ~/Daily-Reddit-Wallpaper
touch change_wallpaper_reddit.sh
chmod +x change_wallpaper_reddit.sh
nano change_wallpaper_reddit.sh

The content of the script is:

#!/bin/sh

# Reference: https://askubuntu.com/a/911958/566421

# Set the script home directory:
SHOME=Daily-Reddit-Wallpaper

# Set the output folder in the home directory to save the Wallpapers to:
DIR=Pictures/Wallpapers

# Set the --time parameter value
TIME=now

# Check if the Desktop Environment is changed:
LAST=$(cat "$HOME/$SHOME/last-desktop-environment.log")
if [ "$1" != "$LAST" ]
then
    # Get the name of the last saved wallpaper image:
    IMG=$(ls -Art $HOME/$DIR | tail -n 1)
    rm $HOME/$DIR/$IMG
fi

# Desktop Environment cases:
if [ -z ${1+x} ] || [ "$1" = "gnome" ] || [ "$1" = "unity" ]
then
    # Set the necessary environment variables - PID=$(pgrep gnome-session -u $USER) - UBUNTU/UNITY/GNOME:
    export GNOME_DESKTOP_SESSION_ID=true
    export DBUS_SESSION_BUS_ADDRESS=$(grep -z DBUS_SESSION_BUS_ADDRESS /proc/$(pgrep gnome-session -n)/environ | cut -d= -f2-)

    # Run the script:
    $HOME/$SHOME/change_wallpaper_reddit.py --time $TIME --output $DIR

elif [ "$1" = "kde" ]
then
    # Set the necessary environment variables - KUBUNTU/PLASMA/KDE:
    export KDE_FULL_SESSION=true
    export DBUS_SESSION_BUS_ADDRESS=$(grep -z DBUS_SESSION_BUS_ADDRESS /proc/$(pgrep startkde -n)/environ | cut -d= -f2-)

    # Run the script:
    $HOME/$SHOME/change_wallpaper_reddit.py --time $TIME --output $DIR

elif [ "$1" = "mate" ]
then
    # Set the necessary environment variables - Ubuntu MATE/MATE:
    export DESKTOP_SESSION=mate
    export DBUS_SESSION_BUS_ADDRESS=$(grep -z DBUS_SESSION_BUS_ADDRESS /proc/$(pgrep mate-session -n)/environ | cut -d= -f2-)

    # Run the script:
    $HOME/$SHOME/change_wallpaper_reddit.py --time $TIME --output $DIR

elif [ "$1" = "lxde" ]
then
    # Set the necessary environment variables - type 'echo $DISPLAY` to find your current display - LUBUNTU/LXDE:
    export DESKTOP_SESSION=Lubuntu
    export DBUS_SESSION_BUS_ADDRESS=$(grep -z DBUS_SESSION_BUS_ADDRESS /proc/$(pgrep lxsession -n)/environ | cut -d= -f2-)
    export DISPLAY=$(w $(id -un) | awk 'NF > 7 && $2 ~ /tty[0-9]+/ {print $3; exit}')

    # Run the script:
    $HOME/$SHOME/change_wallpaper_reddit.py --time $TIME --output $DIR

elif [ "$1" = "xfce4" ]
then
    # Set the necessary environment variables - XUBUNTU/XFCE4:
    export DBUS_SESSION_BUS_ADDRESS=$(grep -z DBUS_SESSION_BUS_ADDRESS /proc/$(pgrep xfce4-session -n)/environ|cut -d= -f2-)

    # Run the script:
    $HOME/$SHOME/change_wallpaper_reddit.py --time $TIME --output $DIR

    # Get the name of the last saved wallpaper image:
    IMG=$(ls -Art $HOME/$DIR | tail -n 1)

    # Since 'change_wallpaper_reddit.py' doesn't work properly with xfce4 we shall set the background manually:
    xfconf-query --channel xfce4-desktop --property /backdrop/screen0/monitor0/workspace0/last-image --set $HOME/$DIR/$IMG

    # Property list:      xfconf-query --channel xfce4-desktop --list
    # Current settings:   xfconf-query -c xfce4-desktop -p /backdrop -lv
    # Set 'zoomed' style: xfconf-query --channel xfce4-desktop --property /backdrop/screen0/monitor0/workspace0/image-style --set 5
    # References:         https://askubuntu.com/q/380550/566421 and https://askubuntu.com/q/414422/566421

else
    echo "Wrong argument. It must be:"
    echo "  - empty (default) = gnome = unity"
    echo "  - kde"
    echo "  - lxde"
    echo "  - mate"
    echo "  - xfce4"
fi

# Save current value of the Desktop Environment variable:
echo "$1" > "$HOME/$SHOME/last-desktop-environment.log"

This script has one argument $1, that determine its behaviour depending of the chosen (from you) desktop environment (DE). The possible values are:

  • gnome or unity or empty (default) - when you use the default Ubuntu DE;
  • kde - when you use KUbuntu DE;
  • lxde - when you use LUbuntu DE;
  • mate - when you use Ubuntu MATE DE;
  • xfce4 - when you use XUbuntu DE.

Also you can customise these initial parameters:

  • SHOME= set the folder where Daily-Reddit-Wallpaper is located into your system.
  • DIR= set the output folder in the home directory to save the Wallpapers to - the default value (Pictures/Wallpapers) is used in the above script.
  • TIME= set the value of the --time parameter of change_wallpaper_reddit.py.

3. Create CronJob (crontab -e), that executes change_wallpaper_reddit.sh (at every hour for example):

  • If you use the default Ubuntu DE, this CronJob could be:

    0 * * * * /home/<your user name>/Daily-Reddit-Wallpaper/change_wallpaper_reddit.sh > /home/<your user name>/Daily-Reddit-Wallpaper/cron.log 2>&1
    

    also this syntax will bring same result:

    0 * * * * /home/<your user name>/Daily-Reddit-Wallpaper/change_wallpaper_reddit.sh gnome > /home/<your user name>/Daily-Reddit-Wallpaper/cron.log 2>&1
    
  • If you use KUbuntu DE, for example, this CronJob could be:

    0 * * * * /home/<your user name>/Daily-Reddit-Wallpaper/change_wallpaper_reddit.sh kde > /home/<your user name>/Daily-Reddit-Wallpaper/cron.log 2>&1
    
  • For troubleshooting check the log file: cat /home/$USER/Daily-Reddit-Wallpaper/cron.log

Voilà. It's working!


References and further reding:

  • How to programmatically find the current value of DISPLAY when DISPLAY is unset? (for use in crontab)
  • Crontab and C program that should be executed into a terminal window
  • Adjust brightness with xrandr and cron job
  • How to determine which is the current user's DE through CLI within SSH or Cron?