Gerar números aleatórios em intervalos específicos

65

Após googling um pouco eu não consegui encontrar uma maneira simples de usar um comando shell para gerar um número inteiro decimal aleatório incluído em um intervalo específico, que é entre um mínimo e um máximo.

Eu li sobre /dev/random , /dev/urandom e $RANDOM , mas nenhuma delas pode fazer o que eu preciso.

Existe outro comando útil ou uma maneira de usar os dados anteriores?

    
por BowPark 04.07.2014 / 14:18

10 respostas

36

Na ferramenta de ferramentas POSIX, você pode usar awk :

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

Não usa isso como uma fonte para gerar senhas ou dados secretos, por exemplo, como a maioria das implementações awk , o número pode ser facilmente adivinhado com base na hora em que o comando foi executado. / p>

Com muitas implementações de awk , esse comando executado duas vezes no mesmo segundo geralmente fornecerá a mesma saída.

    
por 04.07.2014 / 14:45
116

Você pode experimentar shuf do GNU coreutils:

shuf -i 1-100 -n 1
    
por 04.07.2014 / 14:26
25

jot

No BSD e OSX você pode usar jot para retornar um único número aleatório ( -r ) do intervalo min para max , inclusive.

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

Problema de distribuição

Infelizmente, o intervalo e a distribuição de números gerados aleatoriamente são influenciados pelo fato de que jot usa aritmética de ponto flutuante de precisão dupla internamente e printf (3) para formato de saída, o que causa problemas de arredondamento e truncamento. Portanto, os min e max do intervalo são gerados com menos frequência, conforme demonstrado:

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

No OS X 10.11 (El Capitan) isso parece ter sido corrigido:

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

e ...

$ 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

Resolvendo o problema de distribuição

Para versões mais antigas do OS X, felizmente existem várias soluções alternativas. Uma é usar a conversão inteira de printf (3). A única ressalva é que o intervalo máximo agora se torna max+1 . Usando a formatação inteira, obtemos uma distribuição justa em todo o intervalo:

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

A solução perfeita

Por fim, para obter um resultado justo usando a solução alternativa, temos:

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

Tarefa extra

Veja jot (1) para os detalhes de matemática e formatação sangrentos e muitos outros exemplos.

    
por 06.11.2015 / 10:55
11

A variável $RANDOM normalmente não é uma boa maneira de gerar bons valores aleatórios. A saída de /dev/[u]random também precisa ser convertida primeiro.

Uma maneira mais fácil é usar idiomas de nível superior, como, por exemplo, python:

Para gerar uma variável inteira aleatória entre 5 e 10 (5 < = N < = 10), use

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

Não use isso para aplicativos criptográficos.

    
por 04.07.2014 / 15:36
8

Você pode obter o número aleatório em urandom

head -200 /dev/urandom | cksum

Saída:

3310670062 52870

Para recuperar a parte do número acima.

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

Em seguida, a saída é

3310670062

    
por 28.10.2015 / 02:42
7

Para gerar uma variável inteira aleatória entre 5 e 10 (incluindo ambos), use

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

% funciona como um operador de módulo.

Provavelmente, existem maneiras melhores de converter a variável aleatória $RANDOM em um intervalo específico. Não use isso para aplicativos criptográficos ou, caso você precise de variáveis aleatórias reais, com distribuição igual (como para simulações).

    
por 04.07.2014 / 14:29
3

Talvez o UUID (no Linux) possa ser usado para recuperar o número aleatório

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

Para obter o número aleatório entre 70 e 100

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

# echo $(( $RANDOM % 256 )) produzirá um número "aleatório" entre 0-255 nos dialetos * sh modernos.

    
por 24.11.2016 / 04:22
2
cat /dev/urandom | tr -dc 'a-fA-F0-9' | fold -w 8 | head -n 1

Isso gerará um número hexadecimal de 8 dígitos.

    
por 10.02.2016 / 12:41
2

Para ficar totalmente dentro do bash e usar a variável $ RANDOM, mas evite a distribuição desigual:

#!/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 ))
until [ $r -lt $max_RANDOM ]; do
r=$RANDOM
done
echo $(( r % $range + $floor ))

Este exemplo forneceria números aleatórios de 20 a 29.

    
por 11.08.2016 / 20:11