BashでN回のうち1回コマンドを実行する方法


15

コマンドをランダムに実行する方法、たとえば10回のうち1回が必要です。これを行うための組み込みまたはGNU coreutilはありますか?理想的には:

chance 10 && do_stuff

do_stuff10回に1回しか実行されないのはどこですか?スクリプトを記述できることは知っていますが、それはかなり単純なことのように思え、定義された方法があるかどうか疑問に思っていました。


1
これは、bashが妥当な選択であり続けるために、スクリプトが手に負えない状態になっている可能性が非常に高い指標です。より本格的なプログラミング言語、おそらくPythonやRubyなどのスクリプト言語を検討する必要があります。
アレクサンダー-モニカの復活

@Alexanderこれは実際にはスクリプトではなく、1行です。私はcronジョブでこれを使用して、
時々

回答:


40

ではksh、バッシュ、Zshの、ヤシュまたはBusyBoxのsh

[ "$RANDOM" -lt 3277 ] && do_stuff

RANDOMKorn、Bash、Yash、Z、およびBusyBoxシェルの特別な変数は、評価されるたびに0から32767の間の擬似ランダムな10進整数値を生成するため、上記は10分の1のチャンスを(ほぼ)与えます。

これを使用して、少なくともBashでは、質問で説明されているように動作する関数を生成できます。

function chance {
  [[ -z $1 || $1 -le 0 ]] && return 1
  [[ $RANDOM -lt $((32767 / $1 + 1)) ]]
}

引数を提供するために、忘れる、または無効な引数を提供する、そう、1の結果を生成しますchance && do_stuff決してdo_stuff

これは、「1のための一般的な式を使用して、N」を使用$RANDOMしている、[[ $RANDOM -lt $((32767 / n + 1)) ]](⎣32767/与え、N 32768チャンスに⎦+ 1)。値がn32768の因子ではない場合、可能な値の範囲に不均等な分割があるため、バイアスが発生します。


(1/2)この問題の再検討:部品の数に上限があるべきであることは直観的です。たとえば、40.000の部品を持つことはできません。実際、実際の制限はかなり小さくなっています。問題は、整数の除算が各部分の大きさの近似値にすぎないことです。2つの連続したパーツ$((32767/parts+1))が1を超える制限の差をもたらすか、分割の結果(したがって、制限)が同じであるときにパーツの数が1増加するリスクに直面する必要があります。(続き)
アイザック

(2/2)(続き)実際に利用可能な数よりも多くの数を占めます。その式は(32767/n-32767/(n+1))>=1、nを解くと、181.5に制限されます。実際、部品の数は問題なく194個まで実行できました。ただし、195パーツでは、結果の制限は151で、194パーツと同じ結果になります。それは不適合であり、避けるべきです。つまり、部品数(n)の上限は194でなければなりません。制限テストを行うことができます。– [[ -z $1 || $1 -le 1 || $1 -ge 194 ]] && return 1
Isaac

25

非標準ソリューション:

[ $(date +%1N) == 1 ] && do_stuff

ナノ秒単位の現在時刻の最後の桁が1であるかどうかを確認してください!



2
呼び出し[ $(date +%1N) == 1 ] && do_stuffが定期的に発生しないことを確認する必要があります。そうしないと、ランダム性が損なわれます。while true; do [ $(date +1%N) == 1 ] && sleep 1; done抽象的な反例と考えてください。それにもかかわらず、ナノ秒で遊ぶというアイデアは本当に良いです、私はそれを使用すると思うので、+ 1
XavierStuvw

3
@XavierStuvwコードが秒をチェックしていた場合、ポイントがあると思います。しかし、ナノ秒?本当にランダムに表示されるはずです。
エリックドゥミニル

9
@EricDuminil:残念なことに:1)システムクロックは、実際のナノ秒の解像度を提供する契約上の義務はありません(最も近い値に丸めることがありますclock_getres())、2)スケジューラは、たとえば、常に100ナノ秒の境界でタイムスライスを開始することを禁止されていません(クロックが正しい場合でもバイアスを導入します)、3)ランダムな値を取得するためのサポートされている方法は、(通常)/dev/urandomの値の読み取りまたは検査です$RANDOM
ケビン

1
@Kevin:コメントありがとうございます。
エリックドゥミニル

21

使用する代わりに$RANDOMshuf次のコマンドがあります。

[[ $(shuf -i 1-10 -n 1) == 1 ]] && do_stuff

仕事をします。ファイルから行をランダムに選択する場合にも役立ちます。音楽プレイリスト用。


1
そのコマンドを知りませんでした。非常に素晴らしい!
アイゼンナール

12

最初の答えを改善し、達成しようとしていることをより明確にします。

[ $(( $RANDOM % 10 )) == 0 ] && echo "You win" || echo "You lose"

1
$RANDOM % 10$RANDOM10の異なる値の正確な倍数を生成しない限り、バイアスがあります(通常、バイナリコンピューターでは発生しません)
phuclv

1
@phuclvはい、それはと同じバイアスを持ち"$RANDOM" -lt $((32767 / n + 1))ます。
アイゼンナール

はい、バイアスは同じです。10分の1の場合は0.1ではなく0.100006104です(0に対してチェックする場合)。
スティーブンキット

1

ランダム性または周期性が必要かどうかわかりません...周期性の場合:

for i in `seq 1 10 100`; do echo $i;done
1
11
21
31
41
51
61
71
81
91

上記の「$ RANDOM」トリックと組み合わせて、より混moreとしたものを作成できます。たとえば、

for iでseq 1 1000 $RANDOM; エコー$ i; done

HTH :-)

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.