59

Is it possible to run a cron job every 30 seconds without a sleep command?

user15336
  • 743
  • 1
  • 5
  • 8
  • 4
    What is your intention? Is cron the right tool to use for this? – Manuel Faux Aug 02 '09 at 20:56
  • Good question. – Preet Sangha Aug 02 '09 at 20:59
  • For instance, I am currently using cron to change my desktop background picture, to circumvent limitations of the native background image switcher (not diving into subdirectories). If I wanted to switch more often than once per minute, I would run into this cron limitation. (although the native bg switcher has the same limitation) – donquixote Jun 23 '16 at 16:11
  • There are many good answers below with different solutions. With or without sleep. There are also interesting solutions for the process locking issue, which is related. – mit Apr 25 '20 at 04:00

10 Answers10

53

Candidate for the most creative misuse of a Linux command:

nohup watch -n 30 --precise yourprog >/dev/null &

If yourprog consists of:

date +%M.%S.%N >> yourprog.out

then yourprog.out might look like:

50.51.857291267
51.21.840818353
51.51.840910204
52.21.840513307
52.51.842455224
53.21.841195858
53.51.841407587
54.21.840629676

indicating a pretty good level of precision.

Here is an explanation of the parts of the command:

  • nohup - This keeps the command that follows it, watch in this case, from exiting when the terminal exits.
  • watch - This program runs a command repeatedly. Normally the first screenful of output from the command is displayed each time watch runs the command.
  • -n 30 - The interval at which to run the command. In this case it's every thirty seconds.
  • --precise - Without this option, watch runs the command after interval seconds. With it, each start of the command begins on the interval if possible. If this option were not specified in the example, the times would get later and later by more than 30 seconds each time due to the time it takes to launch and execute the command (yourprog).
  • yourprog - The program or command line for watch to execute. If the command line contains characters special to the shell (e.g. space or semicolon) it will need to be quoted.
  • >/dev/null - The greater-than redirects the output of the command being run by watch to a file, /dev/null. That file discards any data written to it. This prevents the output from being written to the screen or, since nohup is being used, it prevents output from being sent to a file called nohup.out.
  • & - The watch command is run in the background and control is returned to the terminal or parent process.

Note that nohup, the redirection of output and the & background control operator are not specific to watch.

Here is an explanation of the example yourprog script:

  • date - Outputs the current date and/or time. It can also set them.
  • +%M.%S.%N - This specifies the output format for date to use. %M is the current minute, %S is the current second and %N is the current nanosecond.
  • >> yourprog.out - This redirects the output of the date command to a file called yourprog.out. The double greater-than causes the output to be appended to the file on each invocation rather than the previous contents being overwritten.

Edit:

Possibly another thing that could be abused (or perhaps it's a legitimate use) is systemd timers.

See systemd/Timers as a cron replacement and Cron vs systemd timers.

I'll try to post an example soon.

Dennis Williamson
  • 60,515
  • 14
  • 113
  • 148
  • 9
    I'm giving +1 for pure cheek – Matt Simmons Aug 16 '09 at 14:31
  • 2
    Would be nice to have a bit more explanation with this answer. The nohup command is new to me. The internet tells me it is to ignore the hangup signal. Which still leaves me confused. – donquixote Jun 23 '16 at 16:19
  • 2
    @donquixote: It's important to recognize that the command as a whole in my answer is not a recommended thing to do, hence the use of the word "misuse". However, in order to clarify things for you a little since there are useful techniques included I'll try to describe a few. The `&` causes the command to run in the background, returning control to the command prompt immediately. Using the `nohup` command causes the backgrounded process (in this case `watch`) to ignore the hangup signal which is sent when the shell exits such as when you close the terminal. ... – Dennis Williamson Jun 23 '16 at 19:26
  • 1
    ... Redirecting output using `>/dev/null` causes the output to be discarded and prevents the creation of a `nohup.out` file which would otherwise be created when standard output is a terminal. – Dennis Williamson Jun 23 '16 at 19:47
  • Ok, so the minimal command would be just `watch -n 30 yourprog`, which means that yourprog will run 30 seconds from now. The rest is to prevent unintended behavior. RIght? – donquixote Jun 23 '16 at 21:36
  • How does watch compare to sleep? Why would one use one instead of the other? Would a solution using sleep have the same problems that need to be circumvented? – donquixote Jun 23 '16 at 21:38
  • 1
    @donquixote: Not just 30 seconds from now, every 30 seconds. The rest is to have it run unattended in the background to be more cron-like. If you wanted to use `sleep`, you would need to write a loop so the process would repeat (`watch` does this repeating for you, as does `cron`). You would still need `nohup` and `&`. An added problem with `sleep` would be time drift. The `--precise` option of `watch` avoids this. Without it or when using `sleep` in a loop, the time interval has the time it takes for the commands or script to run added to it so each run gets later and later than the... – Dennis Williamson Jun 23 '16 at 22:10
  • ... expected time. Please don't use the technique in my answer to run actual production work. – Dennis Williamson Jun 23 '16 at 22:11
  • Maybe add a "Details / Explanation" section to your answer to explain this stuff? – donquixote Jun 24 '16 at 11:24
  • I drafted some enhancements to the original answer. This needs some finish-up work from you, but it is a start. – donquixote Jun 24 '16 at 11:36
  • Perfectly explained ty also do you advise `systemd` or say `watch` or `repeat` bundled with `while` over `cron` on android too. – himanshuxd Jan 13 '20 at 22:08
  • Advise? No. Note the word "misuse" in my answer. – Dennis Williamson Jun 29 '22 at 03:26
39

If your task needs to run that frequently, cron is the wrong tool. Aside from the fact that it simply won't launch jobs that frequently, you also risk some serious problems if the job takes longer to run than the interval between launches. Rewrite your task to daemonize and run persistently, then launch it from cron if necessary (while making sure that it won't relaunch if it's already running).

  • 25
    The part "you also risk some serious problems if the job takes longer to run than the interval between launches." is not true and if it was it would apply equally to jobs that run every 5 minutes, every hour, or every month for that matter. That problem has solutions (using a pidfile or whatever and checking whether the job is already running before running it). So the issue is that cron just won't allow that frequency, but it is incorrect to say that there is something intrinsically wrong in executing a task every less than a minute. – matteo Nov 13 '12 at 21:30
  • 3
    I meant if you don't use a pidfile. If your job runs every X minutes, and takes more than X minutes to finish, you'll end up with jobs stacking up. If your job is also limited by some sort of resource (CPU, network/disk bandwidth, etc), then running more at a time will make it take even longer to finish, and eventually your computer will turn into a thrashing mess. –  Nov 14 '12 at 03:08
  • 3
    You can use `run-one` to ensure a program / even a PHP script isn't starting a duplicate instance. `sudo apt-get install run-one` and call it by `run-one ` – kouton Jul 03 '14 at 10:34
  • 6
    As answers further down show, it is very well possible, albeit a bit hackish. Why is YOU ARE DOING IT WRONG!!!! the accepted answer here, when it doesn't answer the question at all? – Mantriur May 23 '15 at 19:17
  • @Mantriur Because the question's author found it helpful and marked it as the accepted answer? :) But seriously, though, you've already identified the problem yourself: many of the other contemporary answers proposed hackish solutions which would be unwise to use in a production system. (Also, keep in mind that several of the other answers only showed up years after the question was asked, so they weren't available to accept yet!) –  May 23 '15 at 20:39
  • @duskwuff I know, I know. :) It's just something I find annoying. Nothing wrong with answering the question and mentioning good reasons not to use that method. But a simple "don't", no matter how well written, is not an answer to the question and imho belongs into comments. – Mantriur May 23 '15 at 21:10
  • It's too easy to just say "wrong tool". That's not an answer, it's a side suggestion. You never know what's the purpose. For some cases, cron is still the right tool. You won't setup Nomad just for 3 jobs, or to convert 700 legacy cron-syntaxes, do you? Why is cron good enough running every minute, but not every 30s? Does not make sense. Long running tasks are not an argument, either. Daemonize is also not a solution when frequently changing setups are involved. You just need a cron daemon that is able to handle the 6col syntax, thats all. Just like https://github.com/pugnascotia/mantra. – sgohl Oct 02 '19 at 12:25
  • Unfortunately, mantra is not designed to run as a daemon reading a crontab. So there must be an alternative drop-in replacement. there is fcron. cronie, vixie-cron, dkron. Where is the cron daemon with 6col syntax? That would be the correct question, not leaving room for such answers like this accepted answer. – sgohl Oct 02 '19 at 12:28
  • This is not answering any part of the question. – mit Apr 21 '20 at 21:56
  • And the first part of the answer is wrong. As seen from the other answers which offer real solutions, cron can be the answer. Whether cron is a good tool for it depends on the use case and in many cases it is. – mit Apr 25 '20 at 04:22
17

Cron is designed to wake up at every minute, so it is not possible to do it without some hacking, for example sleep like you mentioned.

Balázs Pozsár
  • 2,085
  • 1
  • 14
  • 16
16
* * * * * /path/to/program
* * * * * sleep 30; /path/to/program

Don't forget to write something into your program so that it exits if a previous instance is already running.

#!/bin/sh

if ln -s "pid=$$" /var/pid/myscript.pid; then
  trap "rm /var/pid/myscript.pid" 0 1 2 3 15
else
  echo "Already running, or stale lockfile." >&2
  exit 1
fi

Of course, this still leaves a very small opportunity for failure, so search google for a better solution applicable to your environment.

ghoti
  • 765
  • 5
  • 15
  • 1
    it has been asked: ``without a sleep command`` – philippe May 23 '15 at 21:40
  • 15
    Other visitors finding this question don't care if the sleep command is used :) – donquixote Jun 23 '16 at 21:39
  • Many people come here from google searches that do not exclude sleep.There is nothing wrong about sleep. The OP probably does not care. He is long gone. Read the questions as: "if possible". – mit Apr 25 '20 at 04:05
11

You can do this with third party software.

An option that has worked well for me is frequent-cron

It allows millisecond precision and it gives you the option to defer the next execution until the current one has exited..

0x6A75616E
  • 661
  • 3
  • 10
  • 24
  • 1
    Frequent-cron has worked well for us too and powers many of our production systems. We haven't ever had an issue with it. – Homer6 Oct 30 '13 at 21:01
3

my simplest and favorite solution for this task:

cron entry:
* * * * * flock -w0 /path/to/script /path/to/script

script:
while true;do echo doing something; sleep 10s;done

lazy alternative: :)

* * * * * flock -w0 /path/to/log watch -n 10 echo doing >> /path/to/log

or

* * * * * flock -w0 /path/to/log watch -n 10 /path/to/script

pros

  • use of flock command avoids running the script by multiple instances in the same time. It can be very important in the most cases.
  • flock and watch commands is available on most Linux installs

cons

  • stopping of this kind of "Service" needs two to steps
    • comment out the cron entry
    • kill the script or the watch command
asvany
  • 31
  • 3
  • 2
    Can someone pls explain this to a linux newbie - with pros and cons? Thanks .. – a20 Dec 13 '17 at 15:29
  • @asvany I think I like this solution but as a20, could you post some explanation for the Linux "green" please? ty. – JoelAZ Mar 16 '19 at 01:14
  • I think the syntax for the first flock command is wrong. The first path provided should be the lockfile, so the cron entry should be something like this (my change is in uppercase): `* * * * * flock -w0 /path/to/LOCKFILE /path/to/script` – Christopher Shroba Jun 21 '22 at 13:26
1

Not an exact answer to your question, but I think it could be useful to some people anyway. If you want to run a command every second, you could do it like this. Each minute, it loops through the 60 seconds, runs a script in a sub-shell and sleeps for 1 second. You need to make sure, that you create a locking file (or a similar mechanism) and abort the script.pl accordingly (if you don't want to run it multiple times in parallel).

* * * * * for((i=0; i<60; i++)); do /usr/bin/perl script.pl & sleep 1; done;
ssc-hrep3
  • 111
  • 2
1

One simple strategy for Linux OSes is to make a SystemD service, e.g. /etc/systemd/system/myservice.service:

[Install]
WantedBy=multi-user.target

[Unit]
Description=Bmon
StartLimitIntervalSec=30
StartLimitBurst=2

[Service]
ExecStart=/usr/bin/bash /home/janie/myservice.sh
Restart=always

Then in myservice.sh:

#!/usr/bin/bash
while true
do
  /home/janie/run_every_10_sec
  sleep 10
done

This will accomplish running the command /home/janie/run_every_10_sec every 10 seconds.

To enable myservice.service, run sudo systemctl enable myservice.

1

I'd have a couple of concerns:

(1) sometimes a system gets busy and cannot start things exactly on the 30 second point, it is then possible that at the same time you are running one job another job would pop and then you have 2 (or more) jobs doing the same thing. Depending on the script, there may be some significant interference here. Thus, coding in such a script should contain some code to insure that only one instance of the given scripting is running at the same time.

(2) The script could possibly have a lot of overhead, and consume more system resources than you might want. This is true if you are competing against a lot of other system activities.

Thus as one poster has put it, in this case I'd seriously consider putting in a daemon running with additional processes to ensure it remains running if its of critical importance to your operations.

mdpc
  • 11,698
  • 28
  • 51
  • 65
  • Not answering the question. These are different subjects and belong to the comments. – mit Apr 25 '20 at 04:07
0

A solution, if it's for your own script or if you can wrap it:

  1. Get and remember start time.
  2. If a lock file, which you will be touching later, is present and script has not been running for 60 seconds, wait a second and check again. (e.g. while/sleep)*
  3. If lock file is still present after 60 seconds have elapsed, exit with a stale lock warning.
  4. Touch lock file.
  5. While script has not been running for 60 seconds, loop your actual task with the desired sleep duration.
  6. Delete lock file.
  7. Add as minutely cron.
  8. Bob's your uncle.

Less of a headache than building and monitoring a daemon.

*If you're using PHP, remember clearstatcache().

Mantriur
  • 369
  • 2
  • 13