8

What's the simplest way you know? Using any tool

2
  • 12
    Please define today. Is that less than 24 hours, or same date as today, or something else?
    – Seamus
    Mar 28 at 7:09
  • @Seamus Same date Mar 29 at 7:26
12

In the beginning of your script, just touch a flag somewhere, so that subsequent invocations of that script can check for the existence and age of that flag.

There's some ambiguity in your question. So first, let's assume that you're asking "How to make a script execute only if certain amount of time has passed since the last time the script executed."

#!/bin/bash
flag="/var/tmp/$(basename -- $0).flag"
min_age=$(( 60 * 60 * 24 )) # 24 hours

if [ -e "$flag" ] ;then
  (( $(date +%s) - $(date +%s -r "$flag") > min_age )) || exit 1
fi
touch "$flag"

# Proceed with your script
# ...

But if you're asking "How to make a script execute only if it has not already been executed since midnight"...

#!/bin/bash
flag="/var/tmp/$(basename -- $0).flag"

if [ -e "$flag" ] ;then
  [ $(date +%F) = $(date +%F -r "$flag") ] && exit 1
fi
touch "$flag"

# Proceed with your script
# ...

--

And if you're simply asking "How to run a sctipt at shutdown" -- then that varies widely from distro to distro. You'll most likely need to look into /etc/rc6.d. On my system, for example, I have /etc/rc.d/rc.local_shutdown, where I can add stuff. You'll need to mention what distro you're using.

Or check out this thread... Execute a command before shutdown

12
  • 1
    better to use /var/tmp instead of /tmp. in short: /var/tmp survives reboots, /tmp doesn't. see unix.stackexchange.com/questions/30489/… for details and caveats.
    – cas
    Mar 28 at 5:42
  • 1
    You forgot about run a script on startup (or reboot/shutdown)
    – Hannu
    Mar 28 at 6:00
  • 2
    @Hannu Not really. He can run it at startup, or shutdown, or any time he wants, or as many times he wants, but the script will actually execute only if more than 24 hours have passed since the last time it successfully executed.
    – Pourko
    Mar 28 at 6:04
  • Ahh... ;-) the word automatically not included in the Q. Sorry.
    – Hannu
    Mar 28 at 6:08
  • It might be more flexible to have the script take the timestamp file name (and maybe the time interval) as an explicit argument, and then exit with 0 or 1 depending on if the condition is met or not. So that you could then run .../shouldrun.sh /var/tmp/timestamp-for-thing-x 86400 && .../run-thing-x.sh. But of course it works for a one-use even without that.
    – ilkkachu
    Mar 28 at 9:25
5

Simplest is largely a matter of opinion, but I feel the simplest way to do this is to use cron. You will need some other "ingredients" to accomplish your objective, but cron can serve as the scheduler for starting a script at boot time. This assumes the version of cron on your system offers the @reboot facility; see man 5 crontab to verify the "special" strings are allowed (@reboot, @yearly, etc).

That said, using cron is as simple as editing your user's crontab. From your bash command line:

$ crontab -e

This will open your crontab in your default editor. Add the following line:

@reboot sleep 15; /path/to/your/script >> /path/to/your/iofile.txt 2>&1

This runs your script each time your system boots.

  • Since cron doesn't know the status of any services required in your script, the sleep 15 command is used to give the OS 15 seconds to marshal all required system resources. You may need more or less than this, depending on the resources needed, and other variables.

  • Use full path specifications in your crontab as the environment (in particular the PATH) is different than in your interactive shell.

  • Script output that would go to stderr or stdout should be re-directed to a local file (iofile.txt here). The iofile.txt file will provide an easy way to access any errors thrown by your script - very helpful for debugging!

You have asked that a condition be applied to running your script @reboot: "but only if it has not already been executed today" . This is taken to mean that there is a possibility that the script may have been executed manually by a user, or that the system may have been re-booted previously in the same day.

Meeting that condition of course depends on your definition of "today"; i.e. "today" as in the past 24 hours, or "today" as in on this same date.

For the case that today=24 hours or less, your condition may be satisfied as follows:

#!/bin/bash
LAST_BOOT=$(cat /path/to/your/timestamp.txt)
CURRENT_BOOT=$(date +%s)
ELAPSED_TIME=$((CURRENT_BOOT - LAST_BOOT))
echo $CURRENT_BOOT > /path/to/your/timestamp.txt
# test ELAPSED_TIME < threshold
if [ $((ELAPSED_TIME <= 86400)) ]; then exit; fi

# the balance of your script follows...

Note use of the +%s format for date gives the epoch time; this allows us to subtract the two boot times to check for 24 hours (86,400 seconds).

For the case that today=same date, your condition may be satisfied as follows:

#!/bin/bash
LAST_BOOT=$(cat /path/to/your/timestamp.txt)
CURRENT_BOOT=$(date +%d)
# test for same date
if [ $((CURRENT_BOOT = LAST_BOOT)) ]; then exit; fi 

# the balance of your script follows...

Note the date +%d format provides the date only. We test for equality between the last boot time, and the current time in the if statement which means that the script has already been run on this date.

Alternatively:

After considering all of your comments just now, you may wish to consider anacron. It's not in as wide use as cron, but it does have the advantage that its @daily schedule "will move tasks to different moments so they are run when the system is on". You may also wish to compare its advantages, and its disadvantages compared to cron. If you wish to dig deeper, this may help

6
  • 2
    I don't thinmk the OP was so much asking about how to run a script on startup, rather than how to prevent it from running too often.
    – patilan
    Mar 28 at 9:57
  • @patilan: You may be correct, but if the question is taken at "face value", I have to say it certainly seems that's what he's asking. But then again, he is a "Physics Enthusiast" - not necessarily an "English Enthusiast" :)
    – Seamus
    Mar 28 at 21:58
  • @patilan Correct! Mar 29 at 7:24
  • So @reboot means at startup? I thought it typically meant resetting (like a shutdown but the pc doesn't shutdown and starts again). Is there a @keyword to indicate I want it on every kind of shutdown? (either reset or actual shutdown). Mar 29 at 7:39
  • @PhysicsEnthusiast123: Yeah - typically it does. @reboot means anytime the system is started - either from issuing a reboot at the console/CLI, or the system has been powered down & you start it up. There is no @shutdown keyword. Your questions suggest that I've wasted a lot of time trying to answer the question you asked instead of the one you meant to ask... what do you think???
    – Seamus
    Mar 29 at 7:52
4

You could consider using anacron.

Anacron allows scheduling periodic jobs on computers that are not turned on all the time. To achieve this, it maintains so-called timestamp files that record the last time a job was run. When the computer is on, anacron regularly gets triggered via various mechanisms (startup script, regular cron jobs, systemd timers) and kicks off jobs that are due based on the timestamp files.

With anacron, in order to run a command once per day, you need to put a line like this into /etc/anacrontab:

@daily  0   daily-job   command
  • The first field is the frequency and can be @daily, @weekly or @monthly as well as an arbitrary number of days (e.g., 2 for every 2 days).

  • The second field is the delay to start running the job after anacron gets triggered.

  • The third field is the name of the job.

  • Finally, the fourth field is the command to execute.

On Debian derivatives, you can drop a script into /etc/cron.daily instead, since anacron (if installed) takes over the task of running daily, weekly and monthly cron jobs by default.

Another option is fcron, which allows doing the same (and possibly more), but I do not have personal experience with it.

3
  • Oh wow never heard of those, and sounds like I need because my problem is precisely that the pc isn't always turned on, so I was thinking running it on shutdown could be very useful for me. I'll have to research those. Thanks! Mar 29 at 7:43
  • @Seamus I made the question because I was having a hard time finding a way to run cronjobs in a pc that isn't always turned on. I was already thinking Linux assumes everything is a server running 24/7. That's why I thought maybe the answer was to run on startup/shutdown instead. That might have hinted Zoltan my pc wasn't always on. I'm not sure if anacron/fcron will be what I end up using, but at least now I know they exist (could be useful some day if not today). Mar 29 at 8:09
  • @PhysicsEnthusiast123: That clarification in your OP would have helped your question. I may have a better grasp of it now, and yes, anacron may be better-suited to your use case - Wikipedia has a good article summarizing anacron. The only advantage that cron may offer is that it's pre-installed on virtually every Linux distro - anacron will probably need to be added.
    – Seamus
    Mar 29 at 8:26

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.