Is there a better way to run a command N times in bash?

BashLoops

Bash Problem Overview


I occasionally run a bash command line like this:

n=0; while [[ $n -lt 10 ]]; do some_command; n=$((n+1)); done

To run some_command a number of times in a row -- 10 times in this case.

Often some_command is really a chain of commands or a pipeline.

Is there a more concise way to do this?

Bash Solutions


Solution 1 - Bash

If your range has a variable, use seq, like this:

count=10
for i in $(seq $count); do
    command
done

Simply:

for run in {1..10}; do
  command
done

Or as a one-liner, for those that want to copy and paste easily:

for run in {1..10}; do command; done

Solution 2 - Bash

Using a constant:

for ((n=0;n<10;n++)); do
    some_command; 
done

Using a variable (can include math expressions):

x=10; for ((n=0; n < (x / 2); n++)); do some_command; done

Solution 3 - Bash

Another simple way to hack it:

seq 20 | xargs -Iz echo "Hi there"

run echo 20 times.


Notice that seq 20 | xargs -Iz echo "Hi there z" would output: > Hi there 1
Hi there 2
...

Solution 4 - Bash

If you're using the zsh shell:

repeat 10 { echo 'Hello' }

Where 10 is the number of times the command will be repeated.

Solution 5 - Bash

Using GNU Parallel you can do:

parallel some_command ::: {1..1000}

If you do not want the number as argument and only run a single job at a time:

parallel -j1 -N0 some_command ::: {1..1000}

Watch the intro video for a quick introduction: https://www.youtube.com/playlist?list=PL284C9FF2488BC6D1

Walk through the tutorial (http://www.gnu.org/software/parallel/parallel_tutorial.html). You command line with love you for it.

Solution 6 - Bash

A simple function in the bash config file (~/.bashrc often) could work well.

function runx() {
  for ((n=0;n<$1;n++))
    do ${*:2}
  done
}

Call it like this.

$ runx 3 echo 'Hello world'
Hello world
Hello world
Hello world

Solution 7 - Bash

Another form of your example:

n=0; while (( n++ < 10 )); do some_command; done

Solution 8 - Bash

If you are OK doing it periodically, you could run the following command to run it every 1 sec indefinitely. You can put other custom checks in place to run it n number of times.

watch -n 1 some_command

If you wish to have visual confirmation of changes, append --differences prior to the ls command.

According to the OSX man page, there's also

> The --cumulative option makes highlighting "sticky", presenting a > running display of all positions that have ever changed. The -t > or --no-title option turns off the header showing the interval, > command, and current time at the top of the display, as well as the > following blank line.

Linux/Unix man page can be found here

Solution 9 - Bash

xargs is fast:

#!/usr/bin/bash
echo "while loop:"
n=0; time while (( n++ < 10000 )); do /usr/bin/true ; done

echo -e "\nfor loop:"
time for ((n=0;n<10000;n++)); do /usr/bin/true ; done

echo -e "\nseq,xargs:"
time seq 10000 | xargs -I{} -P1 -n1 /usr/bin/true

echo -e "\nyes,xargs:"
time yes x | head -n10000 |  xargs -I{} -P1 -n1 /usr/bin/true

echo -e "\nparallel:"
time parallel --will-cite -j1 -N0 /usr/bin/true ::: {1..10000}

On a modern 64-bit Linux, gives:

while loop:

real    0m2.282s
user    0m0.177s
sys     0m0.413s

for loop:

real    0m2.559s
user    0m0.393s
sys     0m0.500s

seq,xargs:

real    0m1.728s
user    0m0.013s
sys     0m0.217s

yes,xargs:

real    0m1.723s
user    0m0.013s
sys     0m0.223s

parallel:

real    0m26.271s
user    0m4.943s
sys     0m3.533s

This makes sense, as the xargs command is a single native process that spawns the /usr/bin/true command multiple time, instead of the for and while loops that are all interpreted in Bash. Of course this only works for a single command; if you need to do multiple commands in each iteration the loop, it will be just as fast, or maybe faster, than passing sh -c 'command1; command2; ...' to xargs

The -P1 could also be changed to, say, -P8 to spawn 8 processes in parallel to get another big boost in speed.

I don't know why GNU parallel is so slow. I would have thought it would be comparable to xargs.

Solution 10 - Bash

for _ in {1..10}; do command; done   

Note the underscore instead of using a variable.

Solution 11 - Bash

For one, you can wrap it up in a function:

function manytimes {
    n=0
    times=$1
    shift
    while [[ $n -lt $times ]]; do
        $@
        n=$((n+1))
    done
}

Call it like:

$ manytimes 3 echo "test" | tr 'e' 'E'
tEst
tEst
tEst

Solution 12 - Bash

xargs and seq will help

function __run_times { seq 1 $1| { shift; xargs -i -- "$@"; } }

the view :

abon@abon:~$ __run_times 3  echo hello world
hello world
hello world
hello world

Solution 13 - Bash

All of the existing answers appear to require bash, and don't work with a standard BSD UNIX /bin/sh (e.g., ksh on OpenBSD).

The below code should work on any BSD:

$ echo {1..4}
{1..4}
$ seq 4
sh: seq: not found
$ for i in $(jot 4); do echo e$i; done
e1
e2
e3
e4
$

Solution 14 - Bash

I solved with this loop, where repeat is an integer that represents the loops's number

repeat=10
for n in $(seq $repeat); 
	do
		command1
		command2
    done

Solution 15 - Bash

You can use this command to repeat your command 10 times or more

for i in {1..10}; do **your command**; done

for example

for i in {1..10}; do **speedtest**; done

Solution 16 - Bash

Yet another answer: Use parameter expansion on empty parameters:

# calls curl 4 times 
curl -s -w "\n" -X GET "http:{,,,}//www.google.com"

Tested on Centos 7 and MacOS.

Solution 17 - Bash

For loops are probably the right way to do it, but here is a fun alternative:

echo -e {1..10}"\n" |xargs -n1 some_command

If you need the iteration number as a parameter for your invocation, use:

echo -e {1..10}"\n" |xargs -I@ echo now I am running iteration @

Edit: It was rightly commented that the solution given above would work smoothly only with simple command runs (no pipes, etc.). you can always use a sh -c to do more complicated stuff, but not worth it.

Another method I use typically is the following function:

rep() { s=$1;shift;e=$1;shift; for x in `seq $s $e`; do c=${@//@/$x};sh -c "$c"; done;}

now you can call it as:

rep 3 10 echo iteration @

The first two numbers give the range. The @ will get translated to the iteration number. Now you can use this with pipes too:

rep 1 10 "ls R@/|wc -l"

with give you the number of files in directories R1 .. R10.

Solution 18 - Bash

A little bit naive but this is what I usually remember off the top of my head:

for i in 1 2 3; do
  some commands
done

Very similar to @joe-koberg's answer. His is better especially if you need many repetitions, just harder for me to remember other syntax because in last years I'm not using bash a lot. I mean not for scripting at least.

Solution 19 - Bash

The script file

bash-3.2$ cat test.sh 
#!/bin/bash

echo "The argument is  arg: $1"

for ((n=0;n<$1;n++));
do
  echo "Hi"
done

and the output below

bash-3.2$  ./test.sh 3
The argument is  arg: 3
Hi
Hi
Hi
bash-3.2$

Solution 20 - Bash

How about the alternate form of for mentioned in (bashref)Looping Constructs?

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionbstpierreView Question on Stackoverflow
Solution 1 - BashJoe KobergView Answer on Stackoverflow
Solution 2 - BashBatchyXView Answer on Stackoverflow
Solution 3 - BashmitnkView Answer on Stackoverflow
Solution 4 - BashWilson SilvaView Answer on Stackoverflow
Solution 5 - BashOle TangeView Answer on Stackoverflow
Solution 6 - BashsteelView Answer on Stackoverflow
Solution 7 - BashDennis WilliamsonView Answer on Stackoverflow
Solution 8 - BashPankaj SinghalView Answer on Stackoverflow
Solution 9 - BashJames ScrivenView Answer on Stackoverflow
Solution 10 - BashAli Omary View Answer on Stackoverflow
Solution 11 - BashbtaView Answer on Stackoverflow
Solution 12 - BashfirejoxView Answer on Stackoverflow
Solution 13 - BashcnstView Answer on Stackoverflow
Solution 14 - BashfvlgnnView Answer on Stackoverflow
Solution 15 - BashM.S SarabandiView Answer on Stackoverflow
Solution 16 - BashjcollumView Answer on Stackoverflow
Solution 17 - BashstacksiaView Answer on Stackoverflow
Solution 18 - BashakostadinovView Answer on Stackoverflow
Solution 19 - BashupogView Answer on Stackoverflow
Solution 20 - BashSamBView Answer on Stackoverflow