Belirli bir aralıkta rasgele sayılar üretin


84

Bir miktar googling yaptıktan sonra, belirli bir aralıkta yer alan, minimum ve maksimum arasında olan rasgele bir ondalık tam sayı oluşturmak için bir kabuk komutu kullanmanın basit bir yolunu bulamadım.

Ben okudum /dev/random, /dev/urandomve $RANDOM, ancak bunların hiçbiri ihtiyacım olanı yapabiliriz.

Başka bir yararlı komut veya önceki verileri kullanmanın bir yolu var mı?




Yanıtlar:


45

POSIX araç testinde şunları kullanabilirsiniz awk:

awk -v min=5 -v max=10 'BEGIN{srand(); print int(min+rand()*(max-min+1))}'

Do not En olduğu gibi, şifre veya örneğin gizli verileri oluşturmak için bir kaynak olarak kullanan awkuygulamalar, sayı kolayca çalıştırıldı komut zamana dayalı tahmin edilebilir.

Birçok awkuygulamada, bu komut aynı saniye içinde iki kez çalıştırılırsa size genellikle aynı çıktıyı verir.


1
+1 .. Bir komut dosyasında bir değişkene çıktı atamak için kullanılır (yeni satır karakteri içermeyen ve iki yer için sıfır dolgusu kullanılmadan):x=$(awk -v min=$min_var -v max=$max_var 'BEGIN{srand(); printf("%.2d", int(min+rand()*(max-min+1)))}')
Christopher

Zamana göre mi? 2 ardışık koşuda aynı değeri aldığımdan beri ...
Shai Alon

@ShaiAlon şimdiki zaman srand () için varsayılan tohum değeri olarak kullanılır, bu yüzden genellikle, evet, zamana dayanır, Stéphane'nin cevabında bu konudaki cümlesine bakın. İlk çekirdeği rastgele bir sayı ile değiştirerek bunun üstesinden gelebilirsiniz awk -v min=5 -v max=10 -v seed="$(od -An -N4 -tu4 /dev/urandom)" 'BEGIN{srand(seed+0); print int(min+rand()*(max-min+1))}'. Bunun $RANDOMyerine kullanabilirsiniz , od ... /dev/randomancak o zaman tohum değeriniz göreceli olarak küçük 0 ila 32767 aralığındadır ve dolayısıyla zamanla çıktınızda gözle görülür tekrarlar elde edersiniz.
Ed Morton

141

shufGNU coreutils'inden deneyebilirsiniz :

shuf -i 1-100 -n 1

Bu aynı zamanda Busybox ile çalışır shuf.
cov

Raspbian ve GitBash'ta da çalışıyor.
nPcomp

30

zerre

BSD ve OSX üzerinde kullanabileceğiniz zerre tek rasgele (dönmek için -raralık itibaren) numarayı miniçin maxkapsayıcı.

$ min=5
$ max=10
$ jot -r 1 $min $max

Dağıtım sorunu

Maalesef, rastgele oluşturulan sayıların aralığı ve dağılımı, notun içten çift duyarlıklı kayan nokta aritmetiği ve çıktı formatı için printf (3) kullanması, bu da yuvarlama ve kesme sorunlarına neden olur. Bu nedenle, aralıklar minve maxgösterilenden daha az sıklıkta üretilir:

$ jot -r 100000 5 10 | sort -n | uniq -c
9918  5
20176 6
20006 7
20083 8
19879 9
9938  10

OS X 10.11'de (El Capitan) bu sorun çözülmüş görünüyor:

$ jot -r 100000 5 10 | sort -n | uniq -c
16692 5
16550 6
16856 7
16579 8
16714 9
16609 10  

ve...

$ jot -r 1000000 1 10 | sort -n | uniq -c
100430 1
99965 2
99982 3
99796 4
100444 5
99853 6
99835 7
100397 8
99588 9
99710 10

Dağıtım problemini çözme

OS X'in eski sürümleri için neyse ki birkaç geçici çözüm var. Bunlardan biri printf (3) tamsayı dönüşümünü kullanmak. Tek uyarı, maksimum aralığın şimdi olmasıdır max+1. Tamsayı biçimlendirmesini kullanarak tüm aralık boyunca adil bir dağılım elde ediyoruz:

$ jot -w %i -r 100000 5 11 | sort -n | uniq -c
16756 5
16571 6
16744 7
16605 8
16683 9
16641 10

Mükemmel çözüm

Son olarak, geçici çözümü kullanarak zarların adil bir şekilde atılması için:

$ min=5
$ max_plus1=11  # 10 + 1
$ jot -w %i -r 1 $min $max_plus1

Ekstra ev ödevi

Kanlı matematik ve biçimlendirme detayları ve daha pek çok örnek için nota (1) bakınız .


15

$RANDOMDeğişken normal olarak oluşturulması iyi bir rasgele değerleri için iyi bir yol değildir. /dev/[u]randomİhtiyacın çıktısı da önce dönüştürülmelidir.

Daha kolay bir yol, örneğin python gibi daha yüksek seviyeli dilleri kullanmaktır:

5 ile 10 (5 <= N <= 10) arasında rasgele bir tamsayı değişkeni oluşturmak için,

python -c "import random; print random.randint(5,10)"

Bunu şifreleme uygulamaları için kullanmayın.


Bu faydalı oldu. Çok teşekkür ederim :) Sık sık imzalandığı gibi Unix-> Solaris 10 ile çalıştığından GNU yardımcı programları varsayılan olarak entegre değildir. Ancak bu çalıştı.
propatience

11

Rasgele sayı aracılığıyla alabilirsiniz urandom

head -200 /dev/urandom | cksum

Çıktı:

3310670062 52870

Yukarıdaki sayının bir kısmını almak için.

head -200 /dev/urandom | cksum | cut -f1 -d " "

O zaman çıktı

3310670062


head -200(ya da POSIX eşdeğer head -n 100) ilk 200 döndürür hatları arasında /dev/urandom. /dev/urandombir metin dosyası değildir, bu komut 200 bayttan (tüm 0x0a olanlar, ASCII'deki LF) sonsuza (0xa byte hiçbir zaman döndürülmezse) geri dönebilir, ancak 45k ile 55k arasındaki değerler en muhtemeldir. cksum 32 bitlik bir sayı döndürür, bu nedenle 4 bayttan fazla almak anlamsızdır /dev/urandom.
Stéphane Chazelas

7

5 ile 10 arasında (her ikisi de dahil) rasgele bir tamsayı değişkeni oluşturmak için,

echo $(( RANDOM % (10 - 5 + 1 ) + 5 ))

% modulo operatörü olarak çalışır.

Rasgele değişkeni $RANDOMbelirli bir aralığa dönüştürmenin daha iyi yolları olabilir . Bunu kriptografik uygulamalar için veya gerçek, eşit dağılıma rastgele değişkenlere ihtiyaç duyduğunuz durumlarda (simülasyonlarda olduğu gibi) kullanmayın.


3
$ RANDOM (özellikle eski olanlar, özellikle de bash) olan birçok kabuk uygulamasında, bu rastgele değildir. Çoğu kabukta, sayı 0 ile 65535 arasındadır, bu nedenle genişliği iki olan gücü olmayan herhangi bir aralık olasılık dağılım farklılığına sahip olacaktır. (Bu durumda, 5 ila 8 sayıları 10923/65536, Olası 9 ve 10922/65536 olasılıkları olacaktır). Menzil ne kadar genişse, tutarsızlık da o kadar büyük olur.
Stéphane Chazelas

Üzgünüz, bu 32767 65535 değil, bu yüzden yukarıdaki hesaplama yanlış (ve aslında daha kötü).
Stéphane Chazelas

@ StéphaneChazelas Daha iyi yollar olduğunu yazdığım gibi
aklımdaydı


4

Belki UUID(Linux'ta) rastgele sayıları almak için kullanılabilir.

$ cat /proc/sys/kernel/random/uuid
cdd52826-327d-4355-9737-895f58ad11b4

70Ve arasında rastgele sayı almak için100

POSIXLY_CORRECT=1 awk -F - '{print(("0x"$1) % 30 + 70)}
   ' /proc/sys/kernel/random/uuid

3
cat /dev/urandom | tr -dc 'a-fA-F0-9' | fold -w 8 | head -n 1

Bu 8 basamaklı onaltılık bir sayı üretecektir.


1

Tamamen bash içinde kalmak ve $ RANDOM değişkenini kullanmak, ancak eşit olmayan dağıtımdan kaçınmak için:

#!/bin/bash
range=10 
floor=20

if [ $range -gt 32768 ]; then
echo 'range outside of what $RANDOM can provide.' >&2
exit 1 # exit before entering infinite loop
fi 

max_RANDOM=$(( 2**15/$range*$range ))
r=$RANDOM
until [ $r -lt $max_RANDOM ]; do
r=$RANDOM
done
echo $(( r % $range + $floor ))

Bu örnek, 20'den 29'a kadar rasgele sayılar sağlayacaktır.


$rBir [: -lt: unary operator expectedhatadan kaçınmak için 65535 veya başka bir yüksek değerle başlatılmalıdır .
LawrenceC

Döngü testinden önceki $ r başlatması düzeltildi. @LawrenceC'ye teşekkürler!
Angell'den

0

Dağıtım iyidir:

((i = 1; i <= 100000; i ++)) echo $ ((RANDOM% (20 - 10 + 1) + 10)); bitti | sıralama -n | uniq -c

sayma değeri

9183 10

9109 11

8915 12

9037 13

9100 14

9138 15

9125 16

9261 17

9088 18

8996 19

9048 20

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.