Jawaban:
Gunakan $RANDOM
. Ini sering berguna dalam kombinasi dengan aritmatika shell sederhana. Misalnya, untuk menghasilkan angka acak antara 1 dan 10 (inklusif):
$ echo $((1 + RANDOM % 10))
3
Generator yang sebenarnya ada variables.c
, fungsinya brand()
. Versi yang lebih lama adalah generator linier sederhana. Versi 4.0 bash
menggunakan generator dengan kutipan ke kertas 1985, yang mungkin berarti itu adalah sumber angka pseudorandom yang layak. Saya tidak akan menggunakannya untuk simulasi (dan tentu saja tidak untuk crypto), tetapi mungkin cukup untuk tugas-tugas scripting dasar.
Jika Anda melakukan sesuatu yang memerlukan angka acak serius yang dapat Anda gunakan /dev/random
atau /dev/urandom
jika tersedia:
$ dd if=/dev/urandom count=4 bs=1 | od -t d
$RANDOM % 10
8 dan 9 secara terukur (meskipun secara marginal) kurang mungkin dari 0-7, bahkan jika $RANDOM
merupakan sumber data acak yang kuat.
$RANDOM
rentang adalah 0-32767
angka 0
- 7
petakan ke 3277
berbagai input yang mungkin, tetapi 8
dan 9
hanya dapat diproduksi 3276
dengan cara yang berbeda (karena 32768
dan 32769
tidak mungkin). Ini adalah masalah kecil untuk peretasan cepat, tetapi artinya hasilnya tidak acak acak. Pustaka acak, seperti Java Random
, menawarkan fungsi untuk mengembalikan angka acak seragam dalam kisaran yang diberikan dengan benar, daripada hanya memodulasi angka yang tidak dapat dibagi.
Silakan lihat $RANDOM
:
$RANDOM
adalah fungsi Bash internal (bukan konstanta) yang mengembalikan integer pseudorandom dalam rentang 0 - 32767. Fungsi ini seharusnya tidak digunakan untuk menghasilkan kunci enkripsi.
32767
ada arti khusus?
32767
adalah 2^16 / 2 - 1
batas atas untuk integer 16 bit yang telah ditandatangani.
2^15 - 1
? Ini setara, jadi saya hanya ingin tahu apakah ada konteks yang hilang?
Anda juga dapat menggunakan shuf (tersedia di coreutils).
shuf -i 1-100000 -n 1
shuf -i 1-10 -n 1: syntax error in expression (error token is "1-10 -n 1")
$var
bukan rentang akhir, seperti ini:var=100 && shuf -i 1-${var} -n 1
-n
. Misalnya Hasilkan 5 angka acak antara 1 dan 100 :shuf -i 1-100 -n 5
shuf -i 1-10 -n 10
Anda akan mendapatkan semua angka dari 1 hingga 10 persis satu. Jika Anda menentukan, -n 15
Anda masih akan mendapatkan hanya 10 angka itu sekali saja. Itu hanya mengocok, tidak menghasilkan angka acak.
Coba ini dari shell Anda:
$ od -A n -t d -N 1 /dev/urandom
Di sini, -t d
menentukan bahwa format output harus ditandatangani desimal; -N 1
mengatakan untuk membaca satu byte dari /dev/urandom
.
od -A n -t d -N 1 /dev/urandom |tr -d ' '
Anda juga bisa mendapatkan nomor acak dari awk
awk 'BEGIN {
# seed
srand()
for (i=1;i<=1000;i++){
print int(1 + rand() * 100)
}
}'
srand()
seed adalah waktu CPU saat ini. Jika Anda perlu menentukan seed tertentu, sehingga RNG dapat diduplikasi, gunakan di srand(x)
mana x
seed tersebut. Juga, dikutip dari manual fungsi numerik GNU awk, "implementasi awk yang berbeda menggunakan generator nomor acak yang berbeda secara internal." Hasilnya adalah jika Anda tertarik untuk menghasilkan distribusi statistik, Anda harus mengharapkan sedikit variasi dari satu runtime ke yang berikutnya pada platform yang berbeda (semua berjalan awk
atau gawk
).
Ada $ ACAK. Saya tidak tahu persis bagaimana cara kerjanya. Tapi itu berhasil. Untuk pengujian, Anda dapat melakukan:
echo $RANDOM
Saya suka trik ini:
echo ${RANDOM:0:1} # random number between 1 and 9
echo ${RANDOM:0:2} # random number between 1 and 99
...
${RANDOM:0:1}
memiliki peluang 67,8% untuk memberi Anda 1 atau 2, ${RANDOM:0:2}
hanya memiliki peluang 0,03% untuk memberi Anda satu digit angka (harus 1%), dan keduanya memiliki peluang 0,003% untuk memberi Anda 0 Masih ada kasus penggunaan di mana ini baik-baik saja (mis. Input tidak konsisten).
Angka acak antara 0 dan 9 inklusif.
echo $((RANDOM%10))
$RANDOM
hanya berlaku dari 0 hingga 32767. Seharusnya dikatakan "Angka acak sebagian besar antara 1 dan 3, dengan beberapa sayap";)
Jika Anda menggunakan sistem linux, Anda bisa mendapatkan nomor acak dari / dev / random atau / dev / urandom. Hati-hati / dev / random akan memblokir jika tidak ada angka acak yang cukup. Jika Anda membutuhkan kecepatan lebih dari keacakan gunakan / dev / urandom.
"File" ini akan diisi dengan angka acak yang dihasilkan oleh sistem operasi. Tergantung pada implementasi / dev / random pada sistem Anda jika Anda mendapatkan nomor acak benar atau pseudo. Angka acak yang sebenarnya dihasilkan dengan noise bentuk bantuan yang dikumpulkan dari driver perangkat seperti mouse, hard drive, jaringan.
Anda bisa mendapatkan nomor acak dari file dengan dd
Saya telah mengambil beberapa dari ide-ide ini dan membuat fungsi yang seharusnya bekerja dengan cepat jika banyak angka acak diperlukan.
panggilan od
itu mahal jika Anda membutuhkan banyak nomor acak. Sebagai gantinya saya menyebutnya sekali dan menyimpan 1024 nomor acak dari / dev / urandom. Ketika rand
dipanggil, nomor acak terakhir dikembalikan dan diskalakan. Itu kemudian dihapus dari cache. Ketika cache kosong, 1024 angka acak lainnya dibaca.
Contoh:
rand 10; echo $RET
Mengembalikan angka acak dalam RET antara 0 dan 9 inklusif.
declare -ia RANDCACHE
declare -i RET RAWRAND=$(( (1<<32)-1 ))
function rand(){ # pick a random number from 0 to N-1. Max N is 2^32
local -i N=$1
[[ ${#RANDCACHE[*]} -eq 0 ]] && { RANDCACHE=( $(od -An -tu4 -N1024 /dev/urandom) ); } # refill cache
RET=$(( (RANDCACHE[-1]*N+1)/RAWRAND )) # pull last random number and scale
unset RANDCACHE[${#RANDCACHE[*]}-1] # pop read random number
};
# test by generating a lot of random numbers, then effectively place them in bins and count how many are in each bin.
declare -i c; declare -ia BIN
for (( c=0; c<100000; c++ )); do
rand 10
BIN[RET]+=1 # add to bin to check distribution
done
for (( c=0; c<10; c++ )); do
printf "%d %d\n" $c ${BIN[c]}
done
UPDATE: Itu tidak bekerja dengan baik untuk semua N. Ini juga membuang bit acak jika digunakan dengan N. kecil. Memperhatikan bahwa (dalam hal ini) angka acak 32 bit memiliki cukup entropi untuk 9 angka acak antara 0 dan 9 (10 * 9 = 1.000.000.000 <= 2 * 32) kita dapat mengekstraksi beberapa angka acak dari setiap 32 nilai sumber acak.
#!/bin/bash
declare -ia RCACHE
declare -i RET # return value
declare -i ENT=2 # keep track of unused entropy as 2^(entropy)
declare -i RND=RANDOM%ENT # a store for unused entropy - start with 1 bit
declare -i BYTES=4 # size of unsigned random bytes returned by od
declare -i BITS=8*BYTES # size of random data returned by od in bits
declare -i CACHE=16 # number of random numbers to cache
declare -i MAX=2**BITS # quantum of entropy per cached random number
declare -i c
function rand(){ # pick a random number from 0 to 2^BITS-1
[[ ${#RCACHE[*]} -eq 0 ]] && { RCACHE=( $(od -An -tu$BYTES -N$CACHE /dev/urandom) ); } # refill cache - could use /dev/random if CACHE is small
RET=${RCACHE[-1]} # pull last random number and scale
unset RCACHE[${#RCACHE[*]}-1] # pop read random number
};
function randBetween(){
local -i N=$1
[[ ENT -lt N ]] && { # not enough entropy to supply ln(N)/ln(2) bits
rand; RND=RET # get more random bits
ENT=MAX # reset entropy
}
RET=RND%N # random number to return
RND=RND/N # remaining randomness
ENT=ENT/N # remaining entropy
};
declare -ia BIN
for (( c=0; c<100000; c++ )); do
randBetween 10
BIN[RET]+=1
done
for c in ${BIN[*]}; do
echo $c
done
od -An -tu4 -N40 /dev/urandom
akan menghasilkan 10 bilangan bulat 32 bit yang tidak ditandatangani dan dipisahkan dengan spasi. Anda bisa menyimpannya dalam sebuah array dan menggunakannya sesudahnya. kode Anda tampaknya berlebihan.
Membaca dari file khusus karakter / dev / random atau / dev / urandom adalah cara yang harus dilakukan.
Perangkat ini mengembalikan angka acak ketika dibaca dan dirancang untuk membantu perangkat lunak aplikasi memilih kunci aman untuk enkripsi. Angka acak tersebut diekstraksi dari kumpulan entropi yang disumbangkan oleh berbagai peristiwa acak. {LDD3, Jonathan Corbet, Alessandro Rubini, dan Greg Kroah-Hartman]
Kedua file ini adalah antarmuka untuk pengacakan kernel, khususnya
void get_random_bytes_arch(void* buf, int nbytes)
yang menarik byte benar-benar acak dari perangkat keras jika fungsi tersebut dilakukan dengan perangkat keras (biasanya), atau menarik dari kumpulan entropi (terdiri dari pengaturan waktu antara peristiwa seperti mouse dan keyboard interupsi dan interupsi lainnya yang terdaftar pada SA_SAMPLE_RANDOM).
dd if=/dev/urandom count=4 bs=1 | od -t d
Ini berfungsi, tetapi menulis keluaran yang tidak dibutuhkan dari dd
ke stdout. Perintah di bawah ini hanya memberikan integer yang saya butuhkan. Saya bahkan bisa mendapatkan jumlah bit acak yang ditentukan sesuai kebutuhan dengan penyesuaian bitmask yang diberikan untuk ekspansi aritmatika:
me@mymachine:~/$ x=$(head -c 1 /dev/urandom > tmp && hexdump
-d tmp | head -n 1 | cut -c13-15) && echo $(( 10#$x & 127 ))
Mungkin saya sedikit terlambat, tetapi bagaimana dengan menggunakan jot
untuk menghasilkan angka acak dalam rentang di Bash?
jot -r -p 3 1 0 1
Ini menghasilkan angka acak ( -r
) dengan 3 tempat desimal presisi ( -p
). Dalam kasus khusus ini, Anda akan mendapatkan satu angka antara 0 dan 1 ( 1 0 1
). Anda juga dapat mencetak data berurutan. Sumber nomor acak, menurut manual, adalah:
Angka acak diperoleh melalui arc4random (3) saat tidak ada benih yang ditentukan, dan melalui acak (3) saat benih diberikan.
Berdasarkan jawaban hebat dari @Nelson, @Barun dan @Robert, berikut adalah skrip Bash yang menghasilkan angka acak.
/dev/urandom
yang jauh lebih baik daripada bawaan Bash$RANDOM
#!/usr/bin/env bash
digits=10
rand=$(od -A n -t d -N 2 /dev/urandom |tr -d ' ')
num=$((rand % 10))
while [ ${#num} -lt $digits ]; do
rand=$(od -A n -t d -N 1 /dev/urandom |tr -d ' ')
num="${num}$((rand % 10))"
done
echo $num
Hasilkan angka acak dalam kisaran 0 hingga n (bertanda integer 16-bit). Hasil ditetapkan dalam variabel $ RAND. Sebagai contoh:
#!/bin/bash
random()
{
local range=${1:-1}
RAND=`od -t uI -N 4 /dev/urandom | awk '{print $2}'`
let "RAND=$RAND%($range+1)"
}
n=10
while [ $(( n -=1 )) -ge "0" ]; do
random 500
echo "$RAND"
done
Percabangan acak suatu program atau ya / tidak; 1/0; output benar / salah:
if [ $RANDOM -gt 16383 ]; then # 16383 = 32767/2
echo var=true/1/yes/go_hither
else
echo var=false/0/no/go_thither
fi
dari jika Anda malas mengingat 16383:
if (( RANDOM % 2 )); then
echo "yes"
else
echo "no"
fi