Eu preciso gerar um número de porta aleatória entre 2000-65000
um script de shell. O problema é que $RANDOM
é um número de 15 bits, então estou preso!
PORT=$(($RANDOM%63000+2001))
funcionaria bem se não fosse pela limitação de tamanho.
Alguém tem um exemplo de como eu posso fazer isso, talvez extraindo algo /dev/urandom
e colocando-o dentro de um intervalo?
shuf
é relativamente recente - eu o vi nos sistemas Ubuntu nos últimos dois anos, mas não no atual RHEL / CentOS.shuf
que realmente permita toda a entrada. Isso faz com que seja uma má escolha se você estiver gerando números aleatórios com muita frequência.time for i in {1..1000}; do shuf -i 0-$end -n 1000 > /dev/null; done
e comparandoend=1
aend=65535
mostrou uma melhoria de 25% para a faixa mais curta que ascenderam a cerca de 4 segundos diferença mais de um milhão iterações. E é muito mais rápido do que realizar o cálculo do Bash do OP um milhão de vezes.-n 1
diferenças de tempo insignificantes mostrou, mesmo comend=4000000000
. É bom sabershuf
trabalha inteligente, não é difícil :-)No Mac OS X e no FreeBSD, você também pode usar o jot:
fonte
jot
possui distribuição injusta para o mínimo e o máximo do intervalo (ou seja, 2000 e 65000). Em outras palavras, o mínimo e o máximo serão gerados com menos frequência. Veja minha resposta rápida para obter detalhes e uma solução alternativa.jot
também está disponível na maioria das distribuições GNU / LinuxDe acordo com a página do manual do bash,
$RANDOM
é distribuído entre 0 e 32767; isto é, é um valor de 15 bits não assinado. Supondo que$RANDOM
seja distribuído uniformemente, você pode criar um número inteiro de 30 bits não assinado e distribuído uniformemente da seguinte maneira:Como seu alcance não é 2, uma operação simples do módulo fornecerá quase uma distribuição uniforme, mas com um intervalo de entrada de 30 bits e um intervalo de saída inferior a 16 bits, como no seu caso, isso realmente deve estar perto o suficiente:
fonte
$RANDOM
nem sempre está disponível em todas as conchas. Procurando outra solução$RANDOM
duas vezes. Nos shells que suportam$RANDOM
, um novo valor é gerado toda vez que é referenciado. Portanto, esse código preenche os bits de 0 a 14 com um$RANDOM
valor e preenche os bits de 15 a 29 com outro. Assumindo que$RANDOM
seja uniforme e independente, isso abrange todos os valores de 0 a 2 ** 30-1 sem pular nada.e aqui está um com Python
e um com awk
fonte
RANDOM
não é garantida por POSIX,-S
opção resulta emImportError: No module named random
. Funciona se eu remover isso. Não tenho certeza qual era a intenção do ghostdog para isso.python -S -c "import random; print random.randrange(2000,63000)"
parece funcionar bem. No entanto, quando tento obter um número aleatório entre 1 e 2, pareço sempre obter 1 ... Pensamentos?A maneira geral mais simples que vem à mente é uma linha de código perl:
Você sempre pode usar apenas dois números:
Você ainda precisa recortar no seu alcance. Não é um método geral de números aleatórios de n bits, mas funcionará no seu caso e está tudo dentro do bash.
Se você quiser ser realmente engraçado e ler em / dev / urandom, faça o seguinte:
Isso lerá dois bytes e os imprimirá como um int não assinado; você ainda precisa fazer o seu recorte.
fonte
awk
a versão de outra respostaSe você não é um especialista em bash e pretendia colocar isso em uma variável em um script bash baseado em Linux, tente o seguinte:
VAR=$(shuf -i 200-700 -n 1)
Isso leva a uma faixa de 200 a 700
$VAR
, inclusive.fonte
Aqui está mais um. Eu pensei que iria funcionar em praticamente qualquer coisa, mas a opção aleatória de sort não está disponível na minha caixa de centos no trabalho.
fonte
sort -R
também não está disponível no OS X.$RANDOM
é um número entre 0 e 32767. Você deseja uma porta entre 2000 e 65000. Essas são 63001 portas possíveis. Se mantivermos valores$RANDOM + 2000
entre 2000 e 33500 , cobriremos um intervalo de 31501 portas. Se jogarmos uma moeda e adicionarmos condicionalmente 31501 ao resultado, obteremos mais portas, de 33501 a 65001 . Então, se abandonarmos 65001, obteremos a cobertura exata necessária, com uma distribuição de probabilidade uniforme para todas as portas, ao que parece.Teste
fonte
Você consegue fazer isso
Se você precisar de mais detalhes, consulte Gerador de números aleatórios de scripts de shell .
fonte
Mesmo com ruby:
fonte
A documentação do Bash diz que sempre
$RANDOM
é referenciada, um número aleatório entre 0 e 32767 é retornado. Se somarmos duas referências consecutivas, obtemos valores de 0 a 65534, que cobrem o intervalo desejado de 63001 possibilidades para um número aleatório entre 2000 e 65000.Para ajustá-lo ao intervalo exato, usamos o módulo de soma 63001, que fornecerá um valor de 0 a 63000. Isso, por sua vez, só precisa de um incremento de 2000 para fornecer o número aleatório desejado, entre 2000 e 65000. Isso pode ser resumidos da seguinte forma:
Teste
Correção do cálculo
Aqui está um teste completo de força bruta para a correção do cálculo. Este programa apenas tenta gerar todas as 63001 possibilidades diferentes aleatoriamente, usando o cálculo em teste. O
--jobs
parâmetro deve torná-lo mais rápido, mas não é determinístico (o total de possibilidades geradas pode ser menor que 63001).Para determinar quantas iterações são necessárias para obter uma determinada probabilidade
p/q
de todas as 63001 possibilidades terem sido geradas, acredito que podemos usar a expressão abaixo. Por exemplo, aqui está o cálculo para uma probabilidade maior que 1/2 e aqui para maior que 9/10 .fonte
$RANDOM
é um número inteiro . Com o seu "truque", existem muitos valores que nunca serão alcançados.-1
.$RANDOM
vez disso, precisamos somar dois acessos e não refatorá-los para uma multiplicação por dois, pois$RANDOM
é suposto mudar a cada acesso. Atualizei a resposta com a versão da soma.RANDOM+RANDOM
não vai dar-lhe um uniforme distribuição de números aleatórios entre 0 e 65534.Ou no OS-X, o seguinte funciona para mim:
fonte
PORT=$(($RANDOM%63000+2001))
está perto do que você quer, eu acho.PORT=$(($RANDOM$RANDOM$RANDOM%63000+2001))
contorna a limitação de tamanho que o incomoda. Como o bash não faz distinções entre uma variável numérica e uma variável de sequência, isso funciona perfeitamente bem. O "número"$RANDOM
pode ser concatenado como uma string e, em seguida, usado como um número em um cálculo. Surpreendente!fonte
x=$(( $n%63000 )
é aproximadamente semelhante ax=$(( $n % 65535 )); if [ $x -gt 63000 ]; then x=63000
.Você pode obter o número aleatório através
urandom
head -200 /dev/urandom | cksum
Resultado:
3310670062 52870
Para recuperar a parte do número acima.
head -200 /dev/urandom | cksum | cut -f1 -d " "
Então a saída é
3310670062
Para cumprir sua exigência,
head -200 /dev/urandom |cksum | cut -f1 -d " " | awk '{print $1%63000+2001}'
fonte
É assim que costumo gerar números aleatórios. Então eu uso "NUM_1" como a variável para o número da porta que eu uso. Aqui está um pequeno exemplo de script.
fonte