web-dev-qa-db-ja.com

bashでコマンドをN回実行するためのより良い方法はありますか?

私は時々このようにbashコマンドラインを実行します。

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

some_commandを連続して何度も実行する - この場合は10回。

多くの場合、some_commandは実際には一連のコマンドまたはパイプラインです。

もっと簡潔な方法はありますか?

255
bstpierre
for run in {1..10}
do
  command
done

簡単にコピー&ペーストしたい人のためのワンライナーとして:

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

定数を使う:

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

変数を使用する(数学式を含めることができます):

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

それをハックするためのもう一つの簡単な方法:

seq 20 | xargs -Iz echo "Hi there"

エコーを20回実行します。


seq 20 | xargs -Iz echo "Hi there z"が出力することに注意してください。

こんにちは1
こんにちは2
...

112
mitnk

Zshシェルを使用している場合

repeat 10 { echo 'Hello' }

ここで、10はコマンドが繰り返される回数です。

61
Wilson Silva

GNU Parallelを使用すると、次のことができます。

parallel some_command ::: {1..1000}

引数として数値を必要とせず、一度に1つのジョブだけを実行する場合は、次のようにします。

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

紹介ビデオで簡単な紹介をご覧ください。 https://www.youtube.com/playlist?list=PL284C9FF2488BC6D1

チュートリアルを進めます( http://www.gnu.org/software/parallel/parallel_tutorial.html )。あなたはそれのためにあなたを愛してラインを指揮します。

23
Ole Tange

Bash設定ファイル内の単純な関数(~/.bashrcがよくあります)でうまくいくでしょう。

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

このように呼んでください。

$ runx 3 echo 'Hello world'
Hello world
Hello world
Hello world
14
steel

あなたの例のもう一つの形:

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

xargsfast:です。

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

これは、すべてのBashで解釈されるxargsおよびforのループではなく、whileコマンドが/usr/bin/trueコマンドを複数回生成する単一のネイティブプロセスであるため、意味があります。もちろん、これは単一のコマンドに対してのみ機能します。ループを繰り返すたびに複数のコマンドを実行する必要がある場合は、xargsにsh -c 'command1; command2; ...'を渡すのと同じくらいの速さか、おそらくより速いでしょう。

また、-P1-P8に変更して、並行して8つのプロセスを生成し、速度を大幅に向上させることもできます。

GNU parallelがそんなに遅いのかわかりません。私はそれがxargsに匹敵するだろうと思っていたでしょう。

10
James Scriven

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
7
firejox
for _ in {1..10}; do command; done   

変数を使用する代わりにアンダースコアに注意してください。

5
Ali Omary

一つには、それを関数にまとめることができます:

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
5
bta

定期的に実行しても問題ない場合は、次のコマンドを実行して1秒ごとに無期限に実行できます。 n回実行するために他のカスタムチェックを配置することができます。

watch -n 1 some_command

変更を視覚的に確認したい場合は、lsコマンドの前に--differencesを追加してください。

OSXのmanページによると、

--cumulativeオプションを使用すると、「スティッキー」が強調表示され、これまでに変更されたすべてのポジションが連続して表示されます。 -tまたは--no-titleオプションを指定すると、間隔、コマンド、および現在の時刻を画面上部に表示するヘッダーと、それに続く空白行がオフになります。

Linux/Unixのmanページが見つかります こちら

3
Pankaj Singhal

繰り返しはループの数を表す整数です。

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

既存のすべての答えは 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
$
1
cnst

さらに別の答え:空のパラメータにパラメータ展開を使用します。

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

Centos 7とMacOSでテスト済み。

1
jcollum

ちょっと素朴ですが、これは私が私の頭の上から覚えているものです:

for i in 1 2 3; do
  some commands
done

@ joe-kobergの回答とよく似ています。特にあなたが多くの繰り返しを必要とするなら、彼はより優れています、私がbashをあまり使っていないので、私が他の構文を覚えるのはもっと難しいです。少なくともスクリプトを書くためではないということです。

1
akostadinov

スクリプトファイル

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$
0
upog

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を使ってもっと複雑なことをすることができますが、それだけの価値はありません。

私が使用するもう1つの方法は、通常、以下の機能です。

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 @

最初の2つの数字は範囲を示します。 @は反復数に変換されます。これでパイプでもこれを使うことができます。

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

とディレクトリR1 .. R10内のファイルの数を与えます。

0
stacksia

(bashref)Looping Constructs に記載されているforの代替形式はどうですか。

0
SamB