Bash içinde N komutundan 1 komutu nasıl çalıştırılır


15

Komutu rastgele çalıştırmanın bir yolunu istiyorum, 10 defadan 1'i. Bunu yapmak için yerleşik veya GNU coreutil var mı, ideal olarak şöyle bir şey:

chance 10 && do_stuff

do_stuff10 defada sadece 1 nerede yapılır? Bir senaryo yazabileceğimi biliyorum, ama oldukça basit bir şey gibi görünüyor ve tanımlı bir yol olup olmadığını merak ediyordum.


1
Bu, betiğinizin bash'ın makul bir seçim olmaya devam etmesi için muhtemelen elden çıktığını gösteren oldukça iyi bir göstergedir. Daha eksiksiz bir programlama dili, belki de Python veya Ruby gibi bir komut dosyası dili düşünmelisiniz.
Alexander - Monica'yı eski

@Alexander bu gerçekten bir senaryo değil, sadece bir satır. Bir cron işinde beni her zaman rastgele bildirmek için kullanıyorum ve daha sonra bir şey yapmayı hatırlatmak için
13

Yanıtlar:


40

In kshBash, Zsh, Yash veya BusyBox sh:

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

RANDOMYukarıdaki (yakın) bir tek-in-on şans verir böylece Korn Bash Yash, Z ve BusyBox kabukları özel değişken 0 ile 32767 değerlendirilen var arasında her zaman bir sözde rastgele ondalık tamsayı değeri üretir.

Sorunuzda, en azından Bash'de açıklandığı gibi davranan bir işlev üretmek için bunu kullanabilirsiniz:

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

Bir argüman vermeyi unutmak ya da geçersiz bir argüman sağlamak 1 sonucunu üretecektir, bu yüzden chance && do_stuffasla olmayacaktır do_stuff.

Bu, “1 in n ” için genel formülü kullanır $RANDOM, yani [[ $RANDOM -lt $((32767 / n + 1)) ]]32768'de bir (⎣32767 / n ⎦ + 1) verir. Değerleri n32768 faktörler nedeniyle olası değerler aralığında düzensiz bölünme bir önyargı tanıtmak değildir.


(1/2) Bu konuyu yeniden ziyaret ederken: Parça sayısında bir üst sınır olması sezgiseldir, örneğin 40.000 parçaya sahip olmak mümkün değildir. Aslında gerçek sınır oldukça küçük. Mesele, tamsayı bölümünün, her bir parçanın ne kadar büyük olabileceğinin bir tahmini olmasıdır. İki ardışık parçanın limitin farkının $((32767/parts+1))1'den büyük olması gerekir ya da bölünme sonucu (ve dolayısıyla limit) aynı olurken parça sayısının 1'de artması riskiyle karşı karşıyayız. (devam ..)
Isaac

(2/2) (devamı) Bu, gerçekte mevcut olandan daha fazla sayıyı açıklayacaktır. Bunun formülü (32767/n-32767/(n+1))>=1, ~ 181.5'te bir sınır veren n'nin çözülmesidir. Aslında parça sayısı 194'a kadar çıkabiliyordu. Ancak 195 kısımda, sonuç limiti 151'dir ve 194 kısım ile aynı sonuçtur. Bu uyumsuzdur ve bundan kaçınılmalıdır. Kısacası, parça sayısı (n) için üst sınır 194 olmalıdır. Limit testlerini yapabilirsiniz:[[ -z $1 || $1 -le 1 || $1 -ge 194 ]] && return 1
Isaac

25

Standart olmayan çözüm:

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

Nanosaniye cinsinden geçerli zamanın son basamağının 1 olup olmadığını kontrol edin!


Bu harika.
Eric Duminil

2
Çağrının [ $(date +%1N) == 1 ] && do_stuffdüzenli aralıklarla yapılmadığından emin olmalısınız , aksi takdirde rasgele bozulur. while true; do [ $(date +1%N) == 1 ] && sleep 1; doneSoyut bir karşı örnek olarak düşünün . Bununla birlikte, nanosaniye ile oynama fikri gerçekten iyi, sanırım onu ​​kullanacağım, bu yüzden +1
XavierStuvw

3
@XavierStuvw Kod saniyeler kontrol ederse bir noktaya sahip olacağını düşünüyorum. Ama nanosaniye? Gerçekten rastgele görünmeli.
Eric Duminil

9
@EricDuminil: Ne yazık ki: 1) Sistem saati sözleşmeye bağlı olarak gerçek nanosaniye çözünürlük sağlamakla yükümlü değildir (en yakın olana yuvarlanabilir clock_getres()), 2) Zamanlayıcının örneğin 100 nanosaniyelik bir sınırda her zaman bir zaman dilimi başlatması yasaktır. (saat doğru olsa bile yanlılık getirir), 3) Rasgele değerler elde etmenin desteklenen yolu (genellikle) /dev/urandomdeğerini okumak veya değerini incelemektir $RANDOM.
Kevin

1
@Kevin: Yorum için çok teşekkürler.
Eric Duminil

21

Kullanmanın alternatifi $RANDOMşu shufkomuttur:

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

işi yapacak. Bir dosyadan rasgele seçim yapmak için de yararlıdır, örn. bir müzik çalma listesi için.


1
Bu komutu bilmiyordum. Çok hoş!
Eisenknurr

12

İlk cevabı geliştirmek ve neyi başarmaya çalıştığınızı daha açık hale getirmek:

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

1
$RANDOM % 10$RANDOM(genellikle ikili bir bilgisayarda gerçekleşmeyen) tam olarak 10 farklı değerin katını üretmedikçe bir sapma olacaktır
phuclv

1
@phuclv Evet, aynı önyargıya sahip olacak "$RANDOM" -lt $((32767 / n + 1)).
Eisenknurr

Evet, sapma aynıdır, 10'u 1 arada 10 için 0,1 yerine 0,100006104 (0'a karşı kontrol ederken).
Stephen Kitt

1

Rasgelelik mi yoksa periyodiklik mi istediğinizden emin değilim ... Periyodiklik için:

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

Daha kaotik bir şey üretmek için yukarıdaki "$ RANDOM" hilesi ile karıştırabilirsiniz, örneğin:

i için seq 1 1000 $RANDOM; echo $ i yap; bitti

HTH :-)

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.