What's the simplest way you know? Using any tool
3 Answers
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
-
1better 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.– casMar 28, 2021 at 5:42
-
1
-
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.– PourkoMar 28, 2021 at 6:04
-
-
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.– ilkkachuMar 28, 2021 at 9:25
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, thesleep 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 thePATH
) is different than in your interactive shell.Script output that would go to
stderr
orstdout
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
-
2I 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.– user461766Mar 28, 2021 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" :)– SeamusMar 28, 2021 at 21:58
-
-
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, 2021 at 7:39 -
@PhysicsEnthusiast123: Yeah - typically it does.
@reboot
means anytime the system is started - either from issuing areboot
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???– SeamusMar 29, 2021 at 7:52
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.
-
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, 2021 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, 2021 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 summarizinganacron
. The only advantage thatcron
may offer is that it's pre-installed on virtually every Linux distro -anacron
will probably need to be added.– SeamusMar 29, 2021 at 8:26
today
. Is thatless than 24 hours
, orsame date as today
, or something else?