There's a builtin 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, rosetta stone style.

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."
share|improve this question
Why not: repeat [-t time] [-n number] command [args...]? – Jonathan Leffler Feb 17 '09 at 0:22
8  
Cool. Unfortunately both on my Ubuntu and my AIX repeat is command not found. Can you do a type repeat and let me know where's coming from? – Davide Nov 22 '09 at 23:47
3  
I'm also on Ubuntu and don't have repeat installed. Any information on how to install this would be helpful. – Rory Dec 21 '09 at 13:02
4  
repeat is a builtin command in csh and tcsh. – Keith Thompson Jan 12 '12 at 9:25
1  
@KeithThompson, csh, tcsh and zsh. Though it's more a keyword than a builtin – Stephane Chazelas Oct 21 '12 at 9:54
show 2 more comments

migrated from stackoverflow.com Apr 5 '11 at 9:44

15 Answers

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, forever.

OP has asked for link to OS X version of watch: http://www.macports.org/

share|improve this answer
Aha, thanks! I don't have that on my system (Mac OS X) -- do you have a link? – dreeves Feb 17 '09 at 0:24
2  
you can use MacPorts to install it. sudo port install watch – pope Feb 17 '09 at 0:27
fink has a package... – dmckee Feb 17 '09 at 0:27
5  
Also available in homebrew (brew install watch). – Lyle May 12 '11 at 21:45
2  
+1 For a new powerful tool. I used to while true; do X; sleep Y; done - This is way better. – Adam Matan May 16 '11 at 11:14
show 1 more comment

Bash

while + sleep:

while true
do 
    echo "Hi"
    sleep 1
done
share|improve this answer
Cool, thanks; which shell is that? But note that I'm looking for something you execute as a single command-line command. – dreeves Feb 17 '09 at 0:19
1  
I believe it works as written in a generic Bourne shell, as well. – dmckee Feb 17 '09 at 0:24
@dreeves, using ";" as separator, commands can be execeted in a single line. Look at Toony's answer as a example – bbaja42 Jan 12 '12 at 9:00
5  
sleep 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"; done – David Costa Jan 12 '12 at 10:46

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}'
share|improve this answer
10  
while [ 0 ] is a bad way to write it. It means 0 is a string with length > 0. while [ 1 ] or while [ jeff ] would do the same thing. Better to write while true. – Mikel Apr 5 '11 at 10:17
1  
@Mikel: Or while : – Keith Thompson Jan 12 '12 at 9:27

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?)
}
share|improve this answer
See also this other question – Stephane Chazelas Oct 21 '12 at 9:52

I like the scripts, but an alternate approach would be to use cron...at least for n = m*60

::blushes:: Hangs head in shame. Thanks Jonathan.

share|improve this answer
cron doesn't work at second granularities - minutes are as small as it works with. – Jonathan Leffler Feb 17 '09 at 0:21
Aye, there's that... – dmckee Feb 17 '09 at 0:22

Care to try this out (Bash)?

forever ()   {
    TIMES=shift;
    SLEEP=shift;
    if [ "$TIMES" = "-1" ]; then  
        while true;
        do 
            $@
            sleep $SLEEP
        done
    else
        repeat "$TIMES" $@ 
    fi; }
share|improve this answer
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 Feb 17 '09 at 0:40
2  
repeat is specific to csh and tcsh. – Keith Thompson Jan 12 '12 at 9:42

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 ;)

share|improve this answer
3  
while [ 1 ] only works because 1 is treated as a string, just like while [ -n 1 ]. while [ 0 ] or while [ jeff ] would do the same thing. while true makes much more sense. – Mikel Apr 5 '11 at 10:19

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); 
}
share|improve this answer

You could source this recursive function:

#!/bin/bash
ininterval () {
    delay=$1
    shift
    $*
    sleep $delay
    ininterval $delay $*
}

or add an:

ininterval $*

and call the script.

share|improve this answer

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
share|improve this answer

This solution works in MacOSX 10.7. 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.

share|improve this answer
Did you mean to have a sleep command there? – Keith Thompson Jan 12 '12 at 9:41
2  
while [ 0 ] is an odd way to write an infinite loop; it works because the test command (also known as [) treats a non-empty string as true. while : ; do ... ; done is more idiomatic, or if you prefer you can use while true ; do ... ; done. – Keith Thompson Jan 17 '12 at 8:11

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.

share|improve this answer

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

share|improve this answer
Why the downvote? You can see this is a working solution by copy and pasting the example into a terminal window. – Thomas Bratt Jan 27 at 14:20

... 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!

share|improve this answer

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?

share|improve this answer
5  
Eval!? What for? sleep $1; shift; "$@" or similar would be much better. – Mikel Apr 20 '12 at 2:01

Your Answer

 
or
required, but never shown
discard

By posting your answer, you agree to the privacy policy and terms of service.

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