Saya perlu membuat nomor port acak antara 2000-65000
dari skrip shell. Masalahnya adalah $RANDOM
angka 15-bit, jadi saya mandek!
PORT=$(($RANDOM%63000+2001))
akan bekerja dengan baik jika bukan karena batasan ukuran.
Adakah yang punya contoh bagaimana saya bisa melakukan ini, mungkin dengan mengekstraksi sesuatu dari /dev/urandom
dan mendapatkannya dalam jangkauan?
shuf
ini relatif baru - saya telah melihatnya di sistem Ubuntu dalam beberapa tahun terakhir tetapi tidak RHEL / CentOS saat ini.shuf
benar-benar mengubah seluruh input. Ini membuatnya menjadi pilihan yang buruk jika Anda sering membuat angka acak.time for i in {1..1000}; do shuf -i 0-$end -n 1000 > /dev/null; done
dan membandingkanend=1
untukend=65535
menunjukkan peningkatan sekitar 25% untuk rentang yang lebih pendek yang berjumlah sekitar 4 detik perbedaan lebih dari sejuta iterasi. Dan itu banyak lebih cepat daripada melakukan OP perhitungan Bash satu juta kali.-n 1
menunjukkan perbedaan waktu yang dapat diabaikan, bahkan denganend=4000000000
. Baik untuk mengetahuishuf
bekerja dengan cerdas, tidak sulit :-)Pada Mac OS X dan FreeBSD Anda juga dapat menggunakan jot:
sumber
jot
memiliki distribusi yang tidak adil untuk interval minimum dan maksimum (yaitu, 2000 dan 65000). Dengan kata lain, min dan max akan dihasilkan lebih jarang. Lihat jawaban saya untuk detail dan solusinya.jot
juga tersedia di sebagian besar distribusi GNU / LinuxMenurut halaman manual bash,
$RANDOM
didistribusikan antara 0 dan 32767; yaitu, nilai 15-bit yang tidak ditandatangani. Dengan asumsi$RANDOM
terdistribusi secara merata, Anda dapat membuat integer 30-bit unsigned yang terdistribusi secara merata sebagai berikut:Karena jangkauan Anda bukan kekuatan 2, operasi modulo sederhana hanya akan hampir memberi Anda distribusi yang seragam, tetapi dengan rentang input 30-bit dan rentang output kurang dari 16-bit, seperti yang Anda miliki dalam kasus Anda, ini harus benar-benar cukup dekat:
sumber
$RANDOM
tidak selalu tersedia di semua shell. Mencari solusi lain$RANDOM
dua kali. Pada shell yang mendukung$RANDOM
, nilai baru dihasilkan setiap kali direferensikan. Jadi kode ini mengisi bit 0 hingga 14 dengan satu$RANDOM
nilai & mengisi bit 15 hingga 29 dengan yang lain. Dengan asumsi$RANDOM
seragam & independen, ini mencakup semua nilai dari 0 hingga 2 ** 30-1 tanpa melewatkan apa pun.dan inilah satu dengan Python
dan satu dengan awk
sumber
RANDOM
tidak dijamin oleh POSIX,-S
opsi menghasilkanImportError: No module named random
. Bekerja jika saya menghapusnya. Tidak yakin apa niat ghostdog untuk itu.python -S -c "import random; print random.randrange(2000,63000)"
tampaknya berfungsi dengan baik. Namun, ketika saya mencoba untuk mendapatkan angka acak antara 1 dan 2, saya sepertinya selalu mendapatkan 1 ... Pikiran?Cara umum paling sederhana yang terlintas dalam pikiran adalah perl one-liner:
Anda selalu bisa menggunakan dua angka:
Anda masih harus klip ke rentang Anda. Ini bukan metode angka acak n-bit umum, tetapi ini akan bekerja untuk kasus Anda, dan semuanya ada di dalam bash.
Jika Anda ingin benar-benar lucu dan membaca dari / dev / urandom, Anda bisa melakukan ini:
Itu akan membaca dua byte dan mencetaknya sebagai int tanpa tanda; Anda masih harus melakukan kliping.
sumber
awk
versi dari jawaban lainJika Anda bukan pakar bash dan ingin memasukkan ini ke variabel dalam skrip bash berbasis Linux, coba ini:
VAR=$(shuf -i 200-700 -n 1)
Itu membuat Anda kisaran 200 hingga 700 ke
$VAR
, inklusif.sumber
Ini satu lagi. Saya pikir itu akan bekerja pada apa saja, tetapi opsi acak sort tidak tersedia pada kotak centos saya di tempat kerja.
sumber
sort -R
juga tidak tersedia di OS X.$RANDOM
adalah angka antara 0 dan 32767. Anda menginginkan port antara 2000 dan 65000. Ini adalah kemungkinan 63001 port. Jika kita tetap berpegang pada nilai$RANDOM + 2000
antara 2000 dan 33500 , kita mencakup kisaran 31501 port. Jika kita melempar koin dan menambahkan 31501 secara kondisional ke hasilnya, kita bisa mendapatkan lebih banyak port, dari 33501 ke 65001 . Kemudian jika kita hanya menjatuhkan 65001, kita mendapatkan cakupan tepat yang dibutuhkan, dengan distribusi probabilitas yang seragam untuk semua port, tampaknya.Pengujian
sumber
Kamu bisa melakukan ini
Jika Anda memerlukan detail lebih lanjut, lihat Pembuat Angka Acak Shell Script .
sumber
Sama dengan ruby:
sumber
Dokumentasi Bash mengatakan bahwa setiap kali
$RANDOM
direferensikan, angka acak antara 0 dan 32767 dikembalikan. Jika kami menjumlahkan dua referensi berturut-turut, kami mendapatkan nilai dari 0 hingga 65534, yang mencakup kisaran 63001 kemungkinan yang diinginkan untuk angka acak antara 2000 dan 65000.Untuk menyesuaikannya dengan rentang yang tepat, kami menggunakan jumlah modulo 63001, yang akan memberi kami nilai dari 0 hingga 63000. Ini pada gilirannya hanya membutuhkan kenaikan pada tahun 2000 untuk memberikan angka acak yang diinginkan, antara 2000 dan 65000. Ini bisa menjadi diringkas sebagai berikut:
Pengujian
Ketepatan perhitungan
Berikut ini adalah uji penuh, brute-force untuk kebenaran perhitungan. Program ini hanya mencoba untuk menghasilkan semua 63001 kemungkinan berbeda secara acak, menggunakan perhitungan yang sedang diuji. The
--jobs
parameter harus membuatnya berjalan lebih cepat, tapi tidak deterministik (total kemungkinan dihasilkan mungkin lebih rendah dari 63.001).Untuk menentukan berapa banyak iterasi yang diperlukan untuk mendapatkan probabilitas tertentu
p/q
dari semua 63001 kemungkinan yang telah dihasilkan, saya percaya kita bisa menggunakan ungkapan di bawah ini. Sebagai contoh, di sini adalah perhitungan untuk probabilitas lebih besar dari 1/2 , dan di sini untuk lebih dari 9/10 .sumber
$RANDOM
adalah bilangan bulat . Dengan "trik" Anda, ada banyak nilai yang tidak akan pernah tercapai.-1
.$RANDOM
, dan jangan$RANDOM
mengubah itu menjadi perkalian dua, karena seharusnya berubah pada setiap akses. Saya telah memperbarui jawabannya dengan versi penjumlahan.RANDOM+RANDOM
tidak akan memberi Anda distribusi seragam angka acak antara 0 dan 65534.Atau di OS-X berikut ini berfungsi untuk saya:
sumber
PORT=$(($RANDOM%63000+2001))
dekat dengan apa yang Anda inginkan saya pikir.PORT=$(($RANDOM$RANDOM$RANDOM%63000+2001))
mengatasi batasan ukuran yang mengganggu Anda. Karena bash tidak membuat perbedaan antara variabel angka dan variabel string, ini berfungsi dengan baik. "Angka"$RANDOM
dapat digabungkan seperti string, dan kemudian digunakan sebagai angka dalam perhitungan. Luar biasa!sumber
x=$(( $n%63000 )
kira-kira mirip denganx=$(( $n % 65535 )); if [ $x -gt 63000 ]; then x=63000
.Anda bisa mendapatkan nomor acak
urandom
head -200 /dev/urandom | cksum
Keluaran:
3310670062 52870
Untuk mengambil satu bagian dari nomor di atas.
head -200 /dev/urandom | cksum | cut -f1 -d " "
Maka outputnya adalah
3310670062
Untuk memenuhi kebutuhan Anda,
head -200 /dev/urandom |cksum | cut -f1 -d " " | awk '{print $1%63000+2001}'
sumber
Beginilah biasanya saya menghasilkan angka acak. Lalu saya menggunakan "NUM_1" sebagai variabel untuk nomor port yang saya gunakan. Berikut ini skrip contoh singkat.
sumber