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

后端 未结 19 2105
执笔经年
执笔经年 2020-11-28 00:26

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

相关标签:
19条回答
  • 2020-11-28 01:26

    Another form of your example:

    n=0; while (( n++ < 10 )); do some_command; done
    
    0 讨论(0)
  • 2020-11-28 01:26

    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
    
    0 讨论(0)
  • 2020-11-28 01:29

    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.

    0 讨论(0)
  • 2020-11-28 01:30

    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
    
    0 讨论(0)
  • 2020-11-28 01:30

    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
    $
    
    0 讨论(0)
  • 2020-11-28 01:32

    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.

    0 讨论(0)
提交回复
热议问题