是否有更好的方法在bash中运行命令N次?

我偶尔会像这样运行bash命令行:

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

连续运行some_command多次——在本例中为10次。

通常some_command实际上是一个命令链或管道。

有没有更简洁的方法呢?

316834 次浏览

使用常量:

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

使用变量(可以包括数学表达式):

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

如果你的范围有一个变量使用seq,就像这样:

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

简单:

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

或者作为一行程序,供那些想要轻松复制和粘贴的人使用:

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

(bashref)循环结构中提到的另一种形式的for呢?

首先,你可以把它封装在一个函数中:

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

这样称呼它:

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

你的例子的另一种形式:

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

Xargs和seq会有所帮助

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

视图:

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

For循环可能是正确的方法,但这里有一个有趣的替代方法:

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

如果需要迭代数作为调用的参数,请使用:

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

编辑:正确的评论是,上面给出的解决方案只会在简单的命令运行中顺利工作(没有管道等)。你总是可以使用sh -c来做更复杂的事情,但不值得这样做。

我通常使用的另一种方法是以下函数:

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

现在你可以把它称为:

rep 3 10 echo iteration @

前两个数字给出了范围。@将被转换为迭代数。现在你也可以在管道中使用这个:

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

给出R1目录下的文件数。R10。

另一种简单的破解方法:

seq 20 | xargs -Iz echo "Hi there"

执行echo命令20次。


注意seq 20 | xargs -Iz echo "Hi there z"将输出:

你好1
Hi there 2
…< / p >

使用GNU Parallel你可以做到:

parallel some_command ::: {1..1000}

如果您不希望将数字作为参数,并且一次只运行一个作业:

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

观看介绍视频快速介绍: https://www.youtube.com/playlist?list=PL284C9FF2488BC6D1 < / p > 通过教程(http://www.gnu.org/software/parallel/parallel_tutorial.html)。命令行

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

注意使用下划线而不是变量。

xargs:

#!/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}

在现代64位Linux上,给出:

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

这是有道理的,因为xargs命令是一个单一的本机进程,它多次生成/usr/bin/true命令,而不是在Bash中解释的forwhile循环。当然,这只适用于单个命令;如果你需要在每次循环迭代中执行多个命令,它将和传递sh -c 'command1; command2; ...'给xargs一样快,或者可能更快

-P1也可以更改为,比如说,-P8,以并行生成8个进程,以获得另一个巨大的速度提升。

我不知道GNU并行为什么这么慢。我本以为它可以与xargs相媲美。

bash配置文件中的一个简单函数(通常是~/.bashrc)就可以很好地工作。

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

这样叫它。

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

如果你正在使用zsh shell:

repeat 10 { echo 'Hello' }

其中10是命令将被重复执行的次数。

如果可以定期执行,可以运行以下命令以每1秒无限期地运行一次。您可以放置其他自定义检查,以运行n次。

watch -n 1 some_command

如果你想要视觉确认更改,在ls命令之前追加--differences

根据OSX手册页,还有

-cumulative选项使高亮显示“粘性”,显示一个 运行显示所有曾经改变的位置。- t 或者——no-title选项关闭显示间隔的标题, 命令,并在顶部显示当前时间,以及

Linux/Unix手册页可以找到在这里

所有现有的答案似乎都需要bash,并且不能与标准的BSD UNIX /bin/sh(例如,OpenBSD上的ksh)一起工作。

下面的代码可以在任何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
$

还有另一个答案:在空参数上使用参数展开:

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

在Centos 7和MacOS上测试。

脚本文件

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


echo "The argument is  arg: $1"


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

下面是输出

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

我用这个循环来解决,其中重复是一个整数,表示循环的个数

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

这有点天真,但这是我通常能立即想到的:

for i in 1 2 3; do
some commands
done

和@joe- kobberg的回答很相似。他的更好,特别是如果你需要多次重复,只是更难记住其他语法,因为在过去的几年里,我没有使用bash很多。我的意思是至少不是写脚本。

此命令可重复执行此命令10次或更多次

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

例如

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