Odpowiedzi:
Zastosowanie $RANDOM
. Jest to często przydatne w połączeniu z prostą arytmetyką powłoki. Na przykład, aby wygenerować losową liczbę od 1 do 10 (włącznie):
$ echo $((1 + RANDOM % 10))
3
Rzeczywisty generator jest włączony variables.c
, funkcja brand()
. Starsze wersje były prostym generatorem liniowym. Wersja 4.0 bash
wykorzystuje generator z cytatem do artykułu z 1985 roku, co prawdopodobnie oznacza, że jest to przyzwoite źródło liczb pseudolosowych. Nie użyłbym jej do symulacji (a już na pewno nie do kryptografii), ale prawdopodobnie jest to wystarczające do podstawowych zadań skryptowych.
Jeśli robisz coś, co wymaga poważnych liczb losowych, możesz ich użyć /dev/random
lub /dev/urandom
jeśli są one dostępne:
$ dd if=/dev/urandom count=4 bs=1 | od -t d
$RANDOM % 10
8 i 9 są mierzalne (choć marginalnie) mniej prawdopodobne niż 0–7, nawet jeśli$RANDOM
jest solidnym źródłem danych losowych.
$RANDOM
„s zakres to 0-32767
numery 0
- 7
map do 3277
różnych możliwych wejść, ale 8
i 9
może być wytwarzany tylko 3276
różne sposoby (bo 32768
i 32769
nie są możliwe). Jest to niewielki problem w przypadku szybkich hacków, ale oznacza, że wynik nie jest jednolicie losowy. Biblioteki losowe, takie jak Java Random
, oferują funkcje do prawidłowego zwracania jednolitej liczby losowej w danym zakresie, zamiast po prostu modyfikować liczbę niepodzielną.
Proszę zobaczyć $RANDOM
:
$RANDOM
to wewnętrzna funkcja Bash (nie stała), która zwraca pseudolosową liczbę całkowitą z zakresu 0 - 32767. Nie należy jej używać do generowania klucza szyfrowania.
32767
ma jakieś specjalne znaczenie?
32767
jest 2^16 / 2 - 1
górną granicą 16-bitowej liczby całkowitej ze znakiem.
2^15 - 1
? Jest to równoważne, więc jestem ciekawy, czy brakuje mi jakiegoś kontekstu?
Możesz także użyć shuf (dostępne w 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
zamiast końca zakresu, jak poniżej:var=100 && shuf -i 1-${var} -n 1
-n
. Np. Wygeneruj 5 liczb losowych od 1 do 100 :shuf -i 1-100 -n 5
shuf -i 1-10 -n 10
, otrzymasz wszystkie liczby od 1 do 10 dokładnie jeden. Jeśli określisz -n 15
, nadal dostaniesz tylko te 10 liczb dokładnie raz. To tak naprawdę tylko tasowanie, a nie generowanie liczb losowych.
Wypróbuj to ze swojej powłoki:
$ od -A n -t d -N 1 /dev/urandom
Tutaj -t d
określa, że format wyjściowy powinien być podpisany dziesiętnie; -N 1
mówi, aby przeczytać jeden bajt /dev/urandom
.
od -A n -t d -N 1 /dev/urandom |tr -d ' '
możesz także uzyskać losową liczbę z awk
awk 'BEGIN {
# seed
srand()
for (i=1;i<=1000;i++){
print int(1 + rand() * 100)
}
}'
srand()
ziarnem jest aktualny czas procesora. Jeśli musisz podać konkretny materiał siewny, aby RNG można było powielić, użyj srand(x)
gdzie x
to ziarno. Cytując również z podręcznika funkcji numerycznych GNU awk, „różne implementacje awk używają wewnętrznie różnych generatorów liczb losowych”. Rezultatem jest to, że jeśli jesteś zainteresowany generowaniem rozkładu statystycznego, powinieneś spodziewać się niewielkich różnic między poszczególnymi środowiskami uruchomieniowymi na różnych platformach (wszystkie działające awk
lub gawk
).
Jest $ RANDOM. Nie wiem dokładnie, jak to działa. Ale to działa. Do testowania możesz:
echo $RANDOM
Podoba mi się ta sztuczka:
echo ${RANDOM:0:1} # random number between 1 and 9
echo ${RANDOM:0:2} # random number between 1 and 99
...
${RANDOM:0:1}
ma 67,8% szansy na 1 lub 2, ${RANDOM:0:2}
ma tylko 0,03% szansy na nadanie jednocyfrowej liczby (powinno wynosić 1%), a obie mają 0,003% szansy na 0 Nadal istnieją przypadki użycia, w których jest to w porządku (np. Niespójne dane wejściowe).
Losowa liczba od 0 do 9 włącznie.
echo $((RANDOM%10))
$RANDOM
zmienia się tylko z 0 na 32767. Powinien był powiedzieć „Losowa liczba, głównie między 1 a 3, z kilkoma skrzydłowymi”;)
Jeśli używasz systemu Linux, możesz uzyskać losową liczbę z / dev / random lub / dev / urandom. Bądź ostrożny / dev / random zablokuje się, jeśli nie będzie wystarczającej liczby losowych numerów. Jeśli potrzebujesz prędkości ponad przypadkowością, użyj / dev / urandom.
Te „pliki” zostaną wypełnione losowymi liczbami generowanymi przez system operacyjny. To zależy od implementacji / dev / random w twoim systemie, jeśli otrzymasz prawdziwe lub pseudolosowe liczby. Prawdziwe liczby losowe są generowane za pomocą szumu zebranego ze sterowników urządzeń, takich jak mysz, dysk twardy, sieć.
Możesz pobrać losowe liczby z pliku za pomocą dd
Wziąłem kilka z tych pomysłów i stworzyłem funkcję, która powinna działać szybko, jeśli wymaganych jest wiele liczb losowych.
dzwonienie od
jest drogie, jeśli potrzebujesz wielu losowych numerów. Zamiast tego dzwonię raz i przechowuję 1024 losowe numery z / dev / urandom. Kiedy rand
jest wywoływany, ostatni losowy numer jest zwracany i skalowany. Następnie jest usuwany z pamięci podręcznej. Gdy pamięć podręczna jest pusta, odczytywane są kolejne 1024 liczby losowe.
Przykład:
rand 10; echo $RET
Zwraca losową liczbę w RET od 0 do 9 włącznie.
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
AKTUALIZACJA: To nie działa tak dobrze dla wszystkich N. Marnuje również losowe bity, jeśli jest używane z małą N. Zauważ, że (w tym przypadku) 32-bitowa liczba losowa ma wystarczającą entropię dla 9 liczb losowych od 0 do 9 (10 * 9 = 1 000 000 000 <= 2 * 32) możemy wyodrębnić wiele liczb losowych z każdej 32 losowej wartości źródłowej.
#!/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
wygeneruje 10 losowych 32-bitowych liczb całkowitych bez znaku oddzielonych spacjami. możesz przechowywać go w tablicy i użyć go później. twój kod wydaje się przesadą.
Czytanie z plików specjalnych znaków / dev / random lub / dev / urandom jest właściwą drogą.
Urządzenia te zwracają prawdziwie losowe liczby podczas odczytu i mają pomóc aplikacjom w wyborze bezpiecznych kluczy do szyfrowania. Takie liczby losowe są pobierane z puli entropii, która jest generowana przez różne zdarzenia losowe. {LDD3, Jonathan Corbet, Alessandro Rubini i Greg Kroah-Hartman]
Te dwa pliki są w szczególności interfejsem do randomizacji jądra
void get_random_bytes_arch(void* buf, int nbytes)
który pobiera prawdziwie losowe bajty ze sprzętu, jeśli taka funkcja jest realizowana sprzętowo (zwykle jest), lub pobiera z puli entropii (składającej się z czasów między zdarzeniami, takimi jak przerwania myszy i klawiatury oraz inne przerwania zarejestrowane w SA_SAMPLE_RANDOM).
dd if=/dev/urandom count=4 bs=1 | od -t d
Działa, ale zapisuje niepotrzebne dane wyjściowe z dd
na standardowe wyjście. Poniższe polecenie podaje tylko liczbę całkowitą, której potrzebuję. Mogę nawet uzyskać określoną liczbę losowych bitów według potrzeb, dostosowując maskę bitową podaną dla rozszerzenia arytmetycznego:
me@mymachine:~/$ x=$(head -c 1 /dev/urandom > tmp && hexdump
-d tmp | head -n 1 | cut -c13-15) && echo $(( 10#$x & 127 ))
Może jestem trochę za późno, ale co jot
z generowaniem losowej liczby w zakresie w Bash?
jot -r -p 3 1 0 1
Generuje to -r
liczbę losową ( ) z dokładnością do 3 miejsc po przecinku ( -p
). W tym konkretnym przypadku otrzymasz jedną liczbę od 0 do 1 ( 1 0 1
). Możesz także wydrukować dane sekwencyjne. Źródłem liczby losowej, zgodnie z instrukcją, jest:
Liczby losowe są uzyskiwane przez arc4random (3), gdy nie podano nasion, i przez losowe (3), gdy podano ziarno.
Oparty na świetnych odpowiedziach @Nelson, @Barun i @Robert, oto skrypt Bash, który generuje losowe liczby.
/dev/urandom
czemu jest znacznie lepsza niż wbudowana 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
Wygeneruj liczbę losową z zakresu od 0 do n (16-bitowa liczba całkowita ze znakiem). Zestaw wyników w zmiennej $ RAND. Na przykład:
#!/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
Losowe rozgałęzienie programu lub tak / nie; 1/0; wyjście prawda / fałsz:
if [ $RANDOM -gt 16383 ]; then # 16383 = 32767/2
echo var=true/1/yes/go_hither
else
echo var=false/0/no/go_thither
fi
jeśli leniwy zapamiętać 16383:
if (( RANDOM % 2 )); then
echo "yes"
else
echo "no"
fi