5

I've made a custom directory where I've put a couple of my favourite wallpapers. I made a script which examines this directory, counts the number of PNGs, and then randomly sets one image as a wallpaper. It looks like this:

#!/bin/bash
#number of images in wallpaper folder
cd $HOME/Favourite\ wallpapers/
numImages=`ls *.png | wc -l`

#randomly chose one number
randomNum=$[ ( $RANDOM % $numImages ) + 1 ]

#command to set wallpaper
gsettings set org.gnome.desktop.background picture-uri file://$HOME/Favourite\ wallpapers/00$randomNum.png

Now, how can I make this script runs on each login (this is very easy thou) or once a day if not has been already run on login?

The problem is that I often suspend my Ubuntu and then awake it tomorrow morning, so in this case I never log in again. Setting this script as startup job would not help me as, obviously, when awaken from suspend, I never re-log in. I cannot simply set it via cron job as well because in cases when I do log in, the wallpaper would be changed two times a day.

PS. anyone feel free to use this script with cron (just set your own path and filename template or wait for a solution like mine :)

3
  • run on startup. add to startup programs.
    – Dr_Bunsen
    Jul 14, 2012 at 17:57
  • @Dr_Bunsen Please read it all. What if I awake from suspend? IT then never gets called
    – ubuntico
    Jul 14, 2012 at 17:59
  • You could add it to both .bashrc and your user-specific crontab, and have the script touch a file in /tmp every time it runs, then checking how much time it has passed before it runs again. However, you wallpaper won't change if you aren't logged in at the time when the cron job is scheduled, which might make it necessary to schedule to job with anacron instead. And the length of the above sentence should indicate that you might be better off adopting one of the few available wallpaper rotation applications. Jul 14, 2012 at 18:47

2 Answers 2

5

Set this as a startup application:

#!/bin/bash
# Based on /etc/cron.daily/apt

check_stamp()
{
    stamp="$1"
    interval="$2"

    if [ $interval -eq 0 ]; then
    echo "check_stamp: interval=0"
    # treat as no time has passed
        return 1
    fi

    if [ ! -f $stamp ]; then
    echo "check_stamp: missing time stamp file: $stamp."
    # treat as enough time has passed
        return 0
    fi

    # compare midnight today to midnight the day the stamp was updated
    stamp_file="$stamp"
    stamp=$(date --date=$(date -r $stamp_file --iso-8601) +%s 2>/dev/null)
    if [ "$?" != "0" ]; then
        # Due to some timezones returning 'invalid date' for midnight on
        # certain dates (eg America/Sao_Paulo), if date returns with error
        # remove the stamp file and return 0. See coreutils bug:
        # http://lists.gnu.org/archive/html/bug-coreutils/2007-09/msg00176.html
        rm -f "$stamp_file"
        return 0
    fi

    now=$(date --date=$(date --iso-8601) +%s 2>/dev/null)
    if [ "$?" != "0" ]; then
        # As above, due to some timezones returning 'invalid date' for midnight
        # on certain dates (eg America/Sao_Paulo), if date returns with error
        # return 0.
        return 0
    fi

    delta=$(($now-$stamp))

    # intervall is in days, convert to sec.
    interval=$(($interval*60*60*24))
    echo "check_stamp: interval=$interval, now=$now, stamp=$stamp, delta=$delta (sec)"

    # remove timestamps a day (or more) in the future and force re-check
    if [ $stamp -gt $(($now+86400)) ]; then
         echo "WARNING: file $stamp_file has a timestamp in the future: $stamp"
         rm -f "$stamp_file"
         return 0
    fi

    if [ $delta -ge $interval ]; then
        return 0
    fi

    return 1
}

update_stamp()
{
    stamp="$1"
    touch $stamp
}


STAMP=$1
INTERVAL=$2
export DISPLAY=:0.0

while true; do
    if check_stamp $STAMP $INTERVAL; then
        # Do whatever you want
        /path/to/your/script

        # Update stamp
        update_stamp $STAMP
    fi

    # Sleep 10 min
    sleep 600
done

Replace the /path/to/your/script (inside the while loop) with the path to your script.
Call this script passing first a path to a file that will serve as a stamp followed by an interval in days, for example scriptname /home/user/stampfile 1. It will run endlessly and check the current time against the stamp every 10 minutes (sleep 600). If the difference is greater than the interval it runs your script and updates the stamp.

5
  • How should I set this script run: in .bashrc or in cron or via some other way?
    – ubuntico
    Jul 19, 2012 at 9:09
  • I also receive some illogical errors: mysc.sh: line 9: [: -eq: unary operator expected date: --iso-8601: No such file or directory mysc.sh: line 44: *60*60*24: syntax error: operand expected (error token is "*60*60*24") `
    – ubuntico
    Jul 19, 2012 at 9:14
  • 1
    @ubuntico Just add it to startup programs. Are you passing a file and an interval as command line arguments? I updated the answer, see the example. Jul 19, 2012 at 19:43
  • I haven't. Thanks for the update. I guess I have to create a file which will hold the time stamp. Does it have to be of any extension or a simple touch timespampfile would suffice?
    – ubuntico
    Jul 20, 2012 at 8:48
  • 1
    No, you don't have to create it. There's a touch inside update_stamp function, if the file doesn't exist it'll be created. Jul 20, 2012 at 15:45
1

I created a script called runonce that runs the supplied command only once per 8 hours (configurable). I placed the script into my ~/bin. Then I simply use this script within my ~/.bashrc:

# set PATH so it includes user's private bin if it exists
if [ -d "$HOME/bin" ] ; then
    PATH="$HOME/bin:$PATH"
fi

# Upgrade my dotfiles but not always
runonce ~/.../... supi

# Print quote but not always
runonce myquote -s

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .