There's a built-in Unix command repeat
whose first argument is the number of times to repeat a command, where the command (with any arguments) is specified by the remaining arguments to repeat
.
For example,
% repeat 100 echo "I will not automate this punishment."
will echo the given string 100 times and then stop.
I'd like a similar command – let's call it forever
– that works similarly except the first argument is the number of seconds to pause between repeats, and it repeats forever. For example,
% forever 5 echo "This will get echoed every 5 seconds forever and ever."
I thought I'd ask if such a thing exists before I write it. I know it's like a 2-line Perl or Python script, but maybe there's a more standard way to do this. If not, feel free to post a solution in your favorite scripting language.
PS: Maybe a better way to do this would be to generalize repeat
to take both the number of times to repeat (with -1 meaning infinity) and the number of seconds to sleep between repeats.
The above examples would then become:
% repeat 100 0 echo "I will not automate this punishment."
% repeat -1 5 echo "This will get echoed every 5 seconds forever."
24 Answers 24
Try the watch
command.
Usage: watch [-dhntv] [--differences[=cumulative]] [--help] [--interval=<n>]
[--no-title] [--version] <command>`
So that:
watch -n1 command
will run the command every second (well, technically, every one second plus the time it takes for command
to run as watch
(at least the procps
and busybox
implementations) just sleeps one second in between two runs of command
), forever.
Would you want to pass the command to exec
instead of sh -c
, use -x
option:
watch -n1 -x command
On macOS, you can get watch
from Mac Ports:
port install watch
Or you can get it from Homebrew:
brew install watch
-
3you can use MacPorts to install it. sudo port install watchpope– pope2009年02月17日 00:27:17 +00:00Commented Feb 17, 2009 at 0:27
-
12Also available in homebrew (brew install watch).Lyle– Lyle2011年05月12日 21:45:47 +00:00Commented May 12, 2011 at 21:45
-
46+1 For a new powerful tool. I used to
while true; do X; sleep Y; done
- This is way better.Adam Matan– Adam Matan2011年05月16日 11:14:16 +00:00Commented May 16, 2011 at 11:14 -
14Problem with this tool (on Ubuntu at least) is that it forces fullscreen, so if I'm dumping some periodic info, I lose the previous info.scorpiodawg– scorpiodawg2012年10月12日 01:00:22 +00:00Commented Oct 12, 2012 at 1:00
-
5It is called
cmdwatch
on FreeBSD (from the ports:sysutils/cmdwatch
).Ouki– Ouki2014年03月25日 21:29:49 +00:00Commented Mar 25, 2014 at 21:29
Bash
while
+ sleep
:
while true
do
echo "Hi"
sleep 1
done
Here's the same thing as a shorthand one-liner (From the comments below):
while sleep 1; do echo "Hi"; done
Uses ;
to separate commands and uses sleep 1
for the while
test since it always returns true. You can put more commands in the loop - just separate them with ;
-
3I believe it works as written in a generic Bourne shell, as well.dmckee --- ex-moderator kitten– dmckee --- ex-moderator kitten2009年02月17日 00:24:16 +00:00Commented Feb 17, 2009 at 0:24
-
6@dreeves, using ";" as separator, commands can be execeted in a single line. Look at Toony's answer as a examplebbaja42– bbaja422012年01月12日 09:00:09 +00:00Commented Jan 12, 2012 at 9:00
-
69sleep 1 always returns true so you can use it as the while condition. Not the most readable thing in the world but absolutely legit: while sleep 1; do echo "Hi"; doneDavid Costa– David Costa2012年01月12日 10:46:27 +00:00Commented Jan 12, 2012 at 10:46
-
13@David Costa: You made a reasonable point, but
sleep
doesn’t always return true. Ī̲ used such loops (albeit with longer delay) namely because there is a way to terminate it gracefully with killing the sleep process.Incnis Mrsi– Incnis Mrsi2015年09月12日 22:53:11 +00:00Commented Sep 12, 2015 at 22:53 -
6@IncnisMrsi I didn't think of it, it actually returns zero only when the time has passed and non-zero when it is terminated by a signal. Thanks for pointing it outDavid Costa– David Costa2015年09月13日 09:58:04 +00:00Commented Sep 13, 2015 at 9:58
This is just a shorter version of other while+sleep
answers, if you are running this kind of tasks often as your daily routine, using this saves you from unnecessary key presses, and if your command line starts to get longer understanding this one is a bit easier. But this one starts with sleeping first.
This is generally useful if you need to follow something has one-line output like machine load:
while sleep 1; do uptime; done
-
Yes. This should be documented next to UUOC.Johan– Johan2013年03月15日 09:05:37 +00:00Commented Mar 15, 2013 at 9:05
-
16And if you want it to operate like "watch" you can do
while clear; do date; command;sleep 5; done
Johan– Johan2013年03月15日 09:12:23 +00:00Commented Mar 15, 2013 at 9:12 -
1Wow, thanks for
while sleep
combination, saves keystokes!George Y.– George Y.2016年06月05日 02:34:29 +00:00Commented Jun 5, 2016 at 2:34 -
while sleep ...
is a good solution if you want colored output.watch
does not provide colored output by default (I'm sure there is some way to get it, but this answer is fast and easy.)BRasmussen– BRasmussen2023年11月19日 17:05:22 +00:00Commented Nov 19, 2023 at 17:05 -
Newer versions of
watch
support--color
.Matthew Read– Matthew Read2024年10月18日 20:13:11 +00:00Commented Oct 18, 2024 at 20:13
One problem that all the answers posted so far have is that the time the command is executed can drift. For example, if you do a sleep 10
between commands, and the command takes 2 seconds to run, then it's going to run every 12 seconds; if it takes a variable amount of time to run, then over the long term the time when it runs can be unpredictable.
This might be just what you want; if so, use one of the other solutions, or use this one but simplify the sleep
call.
For one-minute resolution, cron jobs will run at the specified time, regardless of how long each command takes. (In fact a new cron job will launch even if the previous one is still running.)
Here's a simple Perl script that sleeps until the next interval, so for example with an interval of 10 seconds the command might run at 12:34:00, 12:34:10, 12:34:20, etc., even if the command itself takes several seconds. If the command runs more than interval
seconds, the next interval will be skipped (unlike cron). The interval is computed relative to the epoch, so an interval of 86400 seconds (1 day) will run at midnight UTC.
#!/usr/bin/perl
use strict;
use warnings;
if (scalar @ARGV < 2) {
die "Usage: 0ドル seconds command [args...]\n";
}
$| = 1; # Ensure output appears
my($interval, @command) = @ARGV;
# print ">>> interval=$interval command=(@command)\n";
while (1) {
print "sleep ", $interval - time % $interval, "\n";
sleep $interval - time % $interval;
system @command; # TODO: Handle errors (how?)
}
-
See also this other questionStéphane Chazelas– Stéphane Chazelas2012年10月21日 09:52:08 +00:00Commented Oct 21, 2012 at 9:52
-
2simpler in bash to minimize drift (though it may drift over very long usage windows due to the sleep command and bash itself accumulating its tiny execution times):
while :; do sleep 1m & command; wait; done
math– math2017年09月14日 13:53:06 +00:00Commented Sep 14, 2017 at 13:53 -
1@math: Clever. It doesn't work if you have other background processes running in the current shell (
wait
will wait for all of them). That's fixable by changingwait
towait $!
, where$!
is the PID of thesleep
process. Post this as an answer and I'll upvote it. But it does produce some extraneous output in an interactive shell.Keith Thompson– Keith Thompson2017年09月14日 20:59:09 +00:00Commented Sep 14, 2017 at 20:59
I think all the answer here so far are either too convoluted, or instead answer a different question:
- "How to run a program repeatedly so that there are X seconds delay between when the program finished, and the next starts".
The real question was:
- "How to run a program every X seconds"
These are two very different things when the command takes time to finish.
Take for instance the script foo.sh
(pretend this is a program that takes a few seconds to complete).
#!/bin/bash
# foo.sh
echo `date +"%H:%M:%S"` >> output.txt;
sleep 2.5;
# ---
You wish to run this every second, and most would suggest watch -n1 ./foo.sh
, or while sleep 1; do ./foo.sh; done
. However, this gives the output:
15:21:20
15:21:23
15:21:27
15:21:30
15:21:34
Which is not exactly being run every second. Even with the -p
flag, as the man watch
page suggests might solve this, the result is the same.
An easy way to accomplish the desired task, which some touch on, is to run the command in the background. In other words:
while sleep 1; do (./foo.sh &) ; done
And that is all there is to it.
You could run it every 500 ms with sleep 0.5
, or what have you.
-
2Those who voted on different answers, do not understand the elegance of your answer...Serge Stroobandt– Serge Stroobandt2015年06月26日 22:58:59 +00:00Commented Jun 26, 2015 at 22:58
-
3This is good unless your program has side effects. If the program takes longer than the interval, the side effects can interfere (like overwriting a file). If the program waits for something else, and that something else is taking forever, then you're starting more and more background jobs indefinitely. Use with caution.Josephine Moeller– Josephine Moeller2015年07月16日 20:36:53 +00:00Commented Jul 16, 2015 at 20:36
-
9could invert the order of the backgrounding to ensure that not more than one ./foo.sh is run at a time, but no faster than 1 per second:
while :; do sleep 1 & ./foo.sh; wait; done
math– math2017年09月14日 13:57:32 +00:00Commented Sep 14, 2017 at 13:57 -
3Yes, it will drift, a few milliseconds on each loop, but it will. Make
date +"%H:%M:%S.%N"
in foo.sh to see how the fraction will increase slowly on each loop.user232326– user2323262018年07月24日 12:53:02 +00:00Commented Jul 24, 2018 at 12:53 -
Yes, it's true that most answers don't literally address the question. But it's an almost safe bet that they answer what the OP wanted. It would be a safer bet if the OP had actually accepted an answer... But this is good, provided you are aware of possible side effects and you are certain that the average run time of the command is not going to exceed the cycle timeAuspex– Auspex2018年07月26日 11:17:33 +00:00Commented Jul 26, 2018 at 11:17
In bash
:
bash -c 'while [ 0 ]; do echo "I will not automate this punishment in absurdum."; done'
(echo
could be replaced by any command...
Or in perl
:
perl -e 'for (;1;) {print "I will not automate this punishment in absurdum.\n"}'
Where print "I will not automate this punishment in absurdum.\n"
could be replaced with "any" command surrounded with backticks (`).
And for a pause, add a sleep
statement inside the for loop:
bash -c 'while [ 0 ]; do echo "I will not automate this punishment in absurdum."; sleep 1; done'
and
perl -e 'for (;1;) {print "I will not automate this punishment in absurdum.\n"; sleep 1}'
-
18
while [ 0 ]
is a bad way to write it. It means0
is a string with length > 0.while [ 1 ]
orwhile [ jeff ]
would do the same thing. Better to writewhile true
.Mikel– Mikel2011年04月05日 10:17:59 +00:00Commented Apr 5, 2011 at 10:17 -
7@Mikel: Or
while :
Keith Thompson– Keith Thompson2012年01月12日 09:27:58 +00:00Commented Jan 12, 2012 at 9:27
Recent bash>= 4.2 under recent Linux kernel, based answer.
In order to limit execution time, there is no forks! Only built-in are used.
For this, I use read
builtin function instead of sleep
. Unfortunely this won't work with notty sessions.
Quick bash function "repeat
" as requested:
repeat () {
local repeat_times=1ドル repeat_delay=2ドル repeat_foo repeat_sleep
read -t .0001 repeat_foo
if [ $? = 1 ] ;then
repeat_sleep() { sleep 1ドル ;}
else
repeat_sleep() { read -t 1ドル repeat_foo; }
fi
shift 2
while ((repeat_times)); do
((repeat_times=repeat_times>0?repeat_times-1:repeat_times))
"${@}"
((repeat_times))&& ((10#${repeat_delay//.})) &&
repeat_sleep $repeat_delay
done
}
Little test with quoted strings:
repeat 3 0 printf "Now: %(%T)T, Hello %s.\n" -1 Guy
Now: 15:13:43, Hello Guy.
Now: 15:13:43, Hello Guy.
Now: 15:13:43, Hello Guy.
repeat -1 .5 printf "Now: %(%T)T, Hello %s.\n" -1 Guy
Now: 15:14:14, Hello Guy.
Now: 15:14:14, Hello Guy.
Now: 15:14:15, Hello Guy.
Now: 15:14:15, Hello Guy.
Now: 15:14:16, Hello Guy.
Now: 15:14:16, Hello Guy.
Now: 15:14:17, Hello Guy.
Now: 15:14:17, Hello Guy.
Now: 15:14:18, Hello Guy.
Now: 15:14:18, Hello Guy.
^C
Depending on granularity and duration of submitted command...
Under recent Linux kernels, there is a procfile /proc/timer_list
containing time information in nanoseconds.
If you want to run a command exactly once by second, your command has to end in less than a second! And from there, you have to sleep
only the rest of current second.
If the delay is more important and your command doesn't require significant time, you could:
command=(echo 'Hello world.')
delay=10
while :;do
printf -v now "%(%s)T" -1
read -t $(( delay-(now%delay) )) foo
${command[@]}
done.
But if your goal is to obtain finer granularity, you have to:
Use nanoseconds information to wait until begin of a second...
For this, I wrote a little bash function:
# bash source file for nano wait-until-next-second
mapfile </proc/timer_list _timer_list
for ((_i=0;_i<${#_timer_list[@]};_i++));do
((_c+=${#_timer_list[_i]}))
[[ ${_timer_list[_i]} =~ ^now ]] && TIMER_LIST_READ=$_c
[[ ${_timer_list[_i]} =~ offset:.*[1-9] ]] && \
TIMER_LIST_OFFSET=${_timer_list[_i]//[a-z.: ]} && \
break
done
unset _i _timer_list _c
readonly TIMER_LIST_OFFSET TIMER_LIST_READ
waitNextSecondHires() {
local nsnow nsslp
read -N$TIMER_LIST_READ nsnow </proc/timer_list
nsnow=${nsnow%% nsecs*}
nsnow=$((${nsnow##* }+TIMER_LIST_OFFSET))
nsslp=$((2000000000-10#${nsnow:${#nsnow}-9}))
read -t .${nsslp:1} foo
}
After sourcing them, you could:
command=(echo 'Hello world.')
while :;do
waitNextSecondHires
${command[@]}
done.
run ${command[@]}
directly on command line, than compare to
command=(eval "echo 'Hello world.';sleep .3")
while :;do
waitNextSecondHires
${command[@]}
done.
this must give exactly same result.
Hires bash function "repeat
" as requested:
You could source this:
mapfile </proc/timer_list _timer_list
for ((_i=0;_i<${#_timer_list[@]};_i++));do
((_c+=${#_timer_list[_i]}))
[[ ${_timer_list[_i]} =~ ^now ]] && TIMER_LIST_READ=$_c
[[ ${_timer_list[_i]} =~ offset:.*[1-9] ]] && \
TIMER_LIST_OFFSET=${_timer_list[_i]//[a-z.: ]} && \
break
done
unset _i _timer_list _c
readonly TIMER_LIST_OFFSET TIMER_LIST_READ
repeat_hires () {
local repeat_times=1ドル repeat_delay=2ドル repeat_foo repeat_sleep repeat_count
read -t .0001 repeat_foo
if [ $? = 1 ] ;then
repeat_sleep() { sleep 1ドル ;}
else
repeat_sleep() { read -t 1ドル repeat_foo; }
fi
shift 2
printf -v repeat_delay "%.9f" $repeat_delay
repeat_delay=${repeat_delay//.}
read -N$TIMER_LIST_READ nsnow </proc/timer_list
nsnow=${nsnow%% nsec*}
started=${nsnow##* }
while ((repeat_times)); do
((repeat_times=repeat_times>0?repeat_times-1:repeat_times))
"${@}"
((repeat_times)) && ((10#$repeat_delay)) && {
read -N$TIMER_LIST_READ nsnow </proc/timer_list
nsnow=${nsnow%% nsec*}
nsnow=${nsnow##* }
(( (nsnow - started) / 10#$repeat_delay - repeat_count++ )) &&
printf >&2 "WARNING: Command '%s' too long for %f delay.\n" \
"${*}" ${repeat_delay:0:${#repeat_delay}-9
}.${repeat_delay:${#repeat_delay}-9}
printf -v sleep "%010d" $((
10#$repeat_delay - ( ( nsnow - started ) % 10#$repeat_delay ) ))
repeat_sleep ${sleep:0:${#sleep}-9}.${sleep:${#sleep}-9}
}
done
}
Then try it:
time repeat_hires 21 .05 sh -c 'date +%s.%N;sleep .01'
1480867565.152022457
1480867565.201249108
1480867565.251333284
1480867565.301224905
1480867565.351236725
1480867565.400930482
1480867565.451207075
1480867565.501212329
1480867565.550927738
1480867565.601199721
1480867565.651500618
1480867565.700889792
1480867565.750963074
1480867565.800987954
1480867565.853671458
1480867565.901232296
1480867565.951171898
1480867566.000917199
1480867566.050942638
1480867566.101171249
1480867566.150913407
real 0m1.013s
user 0m0.000s
sys 0m0.016s
time repeat_hires 3 .05 sh -c 'date +%s.%N;sleep .05'
1480867635.380561067
WARNING: Command 'sh -c date +%s.%N;sleep .05' too long for 0.050000 delay.
1480867635.486503367
WARNING: Command 'sh -c date +%s.%N;sleep .05' too long for 0.050000 delay.
1480867635.582332617
real 0m0.257s
user 0m0.000s
sys 0m0.004s
-
read -t
is a built-in, whilesleep
is not. This could have border effect (ie hitting [key:return] interrupt quietly the sleep), but this could be treated by testing$foo
F. Hauri - Give Up GitHub– F. Hauri - Give Up GitHub2014年01月29日 17:34:37 +00:00Commented Jan 29, 2014 at 17:34
If your intention is not to display a message to your screen, and if you could afford to repeat the job in terms of minutes, crontab, perhaps, would be your best tool. For example, if you wish to execute your command every minute, you would write something like this in your crontab
file:
* * * * * my_precious_command
Please check out the tutorial for further example. Also, you can set the timings easily using Crontab Code Generator.
Bash and some of its kindred shells have the convenient (( ... ))
notation wherein arithmetic expressions can be evaluated.
So as an answer to your third challenge, where both the repeat count and delay between each repeat should be configurable, here's one way to do it:
repeat=10
delay=1
i=0
while (( i++ < repeat )); do
echo Repetition $i
sleep $delay
done
This answer also suffers from the timing drift covered in Keith's answer.
Perl
#!/usr/bin/env perl
# First argument is number of seconds to sleep between repeats, remaining
# arguments give the command to repeat forever.
$sleep = shift;
$cmd = join(' ', @ARGV);
while(1) {
system($cmd);
sleep($sleep);
}
What if we had both ?
Here's the idea : with only "interval", it repeats forever. With "interval" and "times", it repeats this number of times, separated by "interval".
The usage :
$ loop [interval [times]] command
So, the algorithm will be :
- List item
- if 1ドル contains only digits, it is the interval (default 2)
- if 2ドル contains only digits, it is the number of times (default infinite)
- while loop with these parameters
- sleep "interval"
- if a number of times has been given, decrement a var until it is reached
Therefore :
loop() {
local i=2 t=1 cond
[ -z ${1//[0-9]/} ] && i=1ドル && shift
[ -z ${1//[0-9]/} ] && t=1ドル && shift && cond=1
while [ $t -gt 0 ]; do
sleep $i
[ $cond ] && : $[--t]
$@
done
}
-
Note: it does not work with floats, despite
sleep
does accept them.Baronsed– Baronsed2013年11月11日 22:37:51 +00:00Commented Nov 11, 2013 at 22:37
Try this out (Bash):
forever () {
TIMES=shift;
SLEEP=shift;
if [ "$TIMES" = "-1" ]; then
while true;
do
$@
sleep $SLEEP
done
else
repeat "$TIMES" $@
fi; }
-
I'm not to hot at shell, so improvements welcome. And I don't seem to have a "repeat" command in my distro.Gregg Lind– Gregg Lind2009年02月17日 00:40:26 +00:00Commented Feb 17, 2009 at 0:40
-
3
repeat
is specific to csh and tcsh.Keith Thompson– Keith Thompson2012年01月12日 09:42:46 +00:00Commented Jan 12, 2012 at 9:42 -
2
As mentioned by gbrandt, if the watch
command is available, definitely use it. Some Unix systems, however, don't have it installed by default (at least they don't where I work).
Here's another solution with slightly different syntax and output (works in BASH and SH):
while [ 1 ] ; do
<cmd>
sleep <x>
echo ">>>>>>>>>>>>>" `date` ">>>>>>>>>>>>>>"
done
Edit: I removed some "." in the last echo statement...holdover from my Perl days ;)
-
4
while [ 1 ]
only works because 1 is treated as a string, just likewhile [ -n 1 ]
.while [ 0 ]
orwhile [ jeff ]
would do the same thing.while true
makes much more sense.Mikel– Mikel2011年04月05日 10:19:09 +00:00Commented Apr 5, 2011 at 10:19
You can obtain the power from python interpreter from shell.
python3 -c "import time, os
while True:
os.system('your command')
time.sleep(5)
replace five in any time(sec) you like.
Attention: the return use SHIFT+ENTER to return input in shell. And do not forget to type 4 SPACE indent in each line in while loop.
-
1Note that
python
'sos.system()
executes a shell to interpret the command line, so invokingpython
to run shells in a loop to run a command periodically is a bit overkill. You might as well do everything in the shell.Stéphane Chazelas– Stéphane Chazelas2018年06月26日 11:26:27 +00:00Commented Jun 26, 2018 at 11:26 -
I agree with you. However, there is a 5 second sleep as you described in each loop. Thus the extra cost from starting a new shell can be ignored. If this cost make the period longer than expectation, you can reduce some sleep time as requirement.pah8J– pah8J2018年06月27日 08:09:52 +00:00Commented Jun 27, 2018 at 8:09
I wound up up creating a variant on swalog's answer. With his you had to wait X seconds for the first iteration, I'm also running my in the foreground so..
./foo.sh;while sleep 1; do (./foo.sh) ; done
-
What do the parens around ./foo.sh do? And why the additional ./foo.sh in the front?user unknown– user unknown2022年12月16日 18:15:37 +00:00Commented Dec 16, 2022 at 18:15
Quick, dirty and probably dangerous to boot, but if you're adventurous and know what you're doing, put this into repeat.sh
and chmod 755
it,
while true
do
eval 1ドル
sleep 2ドル
done
Invoke it with ./repeat.sh <command> <interval>
My spidey sense says this is probably an evil way of doing this, is my spidey sense right?
-
8Eval!? What for?
sleep 1ドル; shift; "$@"
or similar would be much better.Mikel– Mikel2012年04月20日 02:01:16 +00:00Commented Apr 20, 2012 at 2:01 -
Dunno why this is -2. eval may be overkill... except when you need it. Eval lets you get things like redirection onto the command line.Johan– Johan2013年03月15日 09:07:42 +00:00Commented Mar 15, 2013 at 9:07
You could run a script from init (adding a line to /etc/inittab). This script must run your command, sleep for the time you want to wait until run the script again, and exit it. Init will start your script again after exit.
To repeatedly run a command in a console window I usually run something like this:
while true; do (run command here); done
This works for multiple commands as well, for example, to display a continually updating clock in a console window:
while true; do clear; date; sleep 1; done
-
Why the downvote? You can see this is a working solution by copy and pasting the example into a terminal window.Thomas Bratt– Thomas Bratt2013年01月27日 14:20:32 +00:00Commented Jan 27, 2013 at 14:20
-
I think you got down voted because it is a little bit dangerous and consumes the CPU.ojblass– ojblass2013年07月06日 20:22:33 +00:00Commented Jul 6, 2013 at 20:22
#! /bin/sh
# Run all programs in a directory in parallel
# Usage: run-parallel directory delay
# Copyright 2013 by Marc Perkel
# docs at http://wiki.junkemailfilter.com/index.php/How_to_run_a_Linux_script_every_few_seconds_under_cron"
# Free to use with attribution
if [ $# -eq 0 ]
then
echo
echo "run-parallel by Marc Perkel"
echo
echo "This program is used to run all programs in a directory in parallel"
echo "or to rerun them every X seconds for one minute."
echo "Think of this program as cron with seconds resolution."
echo
echo "Usage: run-parallel [directory] [delay]"
echo
echo "Examples:"
echo " run-parallel /etc/cron.20sec 20"
echo " run-parallel 20"
echo " # Runs all executable files in /etc/cron.20sec every 20 seconds or 3 times a minute."
echo
echo "If delay parameter is missing it runs everything once and exits."
echo "If only delay is passed then the directory /etc/cron.[delay]sec is assumed."
echo
echo 'if "cronsec" is passed then it runs all of these delays 2 3 4 5 6 10 12 15 20 30'
echo "resulting in 30 20 15 12 10 6 5 4 3 2 executions per minute."
echo
exit
fi
# If "cronsec" is passed as a parameter then run all the delays in parallel
if [ 1ドル = cronsec ]
then
0ドル 2 &
0ドル 3 &
0ドル 4 &
0ドル 5 &
0ドル 6 &
0ドル 10 &
0ドル 12 &
0ドル 15 &
0ドル 20 &
0ドル 30 &
exit
fi
# Set the directory to first prameter and delay to second parameter
dir=1ドル
delay=2ドル
# If only parameter is 2,3,4,5,6,10,12,15,20,30 then automatically calculate
# the standard directory name /etc/cron.[delay]sec
if [[ "1ドル" =~ ^(2|3|4|5|6|10|12|15|20|30)$ ]]
then
dir="/etc/cron.1ドルsec"
delay=1ドル
fi
# Exit if directory doesn't exist or has no files
if [ ! "$(ls -A $dir/)" ]
then
exit
fi
# Sleep if both $delay and $counter are set
if [ ! -z $delay ] && [ ! -z $counter ]
then
sleep $delay
fi
# Set counter to 0 if not set
if [ -z $counter ]
then
counter=0
fi
# Run all the programs in the directory in parallel
# Use of timeout ensures that the processes are killed if they run too long
for program in $dir/* ; do
if [ -x $program ]
then
if [ "0$delay" -gt 1 ]
then
timeout $delay $program &> /dev/null &
else
$program &> /dev/null &
fi
fi
done
# If delay not set then we're done
if [ -z $delay ]
then
exit
fi
# Add delay to counter
counter=$(( $counter + $delay ))
# If minute is not up - call self recursively
if [ $counter -lt 60 ]
then
. 0ドル $dir $delay &
fi
# Otherwise we're done
Easy way to repeat a job from crontab with an interval less than one minute (20 seconds example) :
crontab: * * * * * script.sh
script.sh:
#!/bin/bash
>>type your commands here.
sleep 20
>>retype your commands here.
sleep 20
>>retype your commands here.
-
Have you heard of loops? Invented about 60 years ago or more.user unknown– user unknown2022年12月16日 18:12:36 +00:00Commented Dec 16, 2022 at 18:12
With zsh
and a sleep
implementation that accepts floating-point arguments:
typeset -F SECONDS=0 n=0
repeat 100 {cmd; sleep $(((n+=3) - SECONDS))}
Or for forever
:
for ((;;)) {cmd; sleep $(((n+=3) - SECONDS))}
If your sleep
doesn't support floats, you can always redefine it as a wrapper around zsh
's zselect
builtin:
zmodload zsh/zselect
sleep() zselect -t $(((1ドル * 100) | 0))
This solution works on Mac OS X v10.7 (Lion). It works wonderfully.
bash -c 'while [ 0 ]; do \
echo "I will not automate this punishment in absurdum."; done'
In my case
bash -c 'while [ 0 ]; do ls; done'
or
bash -c 'while [ 0 ]; do mv "Desktop/* Documents/Cleanup"; done'
to clean up my desktop constantly.
-
2Did you mean to have a
sleep
command there?Keith Thompson– Keith Thompson2012年01月12日 09:41:46 +00:00Commented Jan 12, 2012 at 9:41 -
6
while [ 0 ]
is an odd way to write an infinite loop; it works because thetest
command (also known as[
) treats a non-empty string as true.while : ; do ... ; done
is more idiomatic, or if you prefer you can usewhile true ; do ... ; done
.Keith Thompson– Keith Thompson2012年01月17日 08:11:27 +00:00Commented Jan 17, 2012 at 8:11
until ! sleep 60; do echo $(date); command; command; command; done
works for me.
- I don ́t need it exactly every 60 seconds
- "watch" does not watch commands on all systems
- "watch" can take only one command (or a script file)
- putting the sleep in the condition instead of the body makes the loop better interruptable (so a claim in a reply to a similar question on stackoverflow. unfortunately I can find it at the moment)
- I want to execute it once before the delay, so I use until instead of while
-
I just noticed that "until" apparently executes the sleep before the first iteration too. is there any way of putting the condition at the end of the loop in bash?Titus– Titus2016年06月11日 13:04:54 +00:00Commented Jun 11, 2016 at 13:04
... I wonder how much complicated solutions can be created when solving this problem.
It can be so easy...
open /etc/crontab
put there 1 next line to the end of file like:
*/NumberOfSeconds * * * * user /path/to/file.sh
If you want to run something every 1 second, just put there:
*/60 * * * * root /path/to/file.sh
where that file.sh could be chmod 750 /path/to/file.sh
and inside of that file.sh should be:
#!/bin/bash
#What does it do
#What is it runned by
your code or commands
and thats all!
ENJOY!
type repeat
and let me know where's coming from?repeat
is a builtin command in csh and tcsh.