Tạo số ngẫu nhiên trong phạm vi cụ thể


84

Sau khi googling một chút, tôi không thể tìm thấy một cách đơn giản để sử dụng lệnh shell để tạo một số nguyên thập phân ngẫu nhiên được bao gồm trong một phạm vi cụ thể, đó là giữa tối thiểu và tối đa.

Tôi đọc về /dev/random, /dev/urandom$RANDOM, nhưng không ai trong số này có thể làm những gì tôi cần.

Có một lệnh hữu ích khác, hoặc một cách để sử dụng dữ liệu trước đó?


2
Xem Câu hỏi và trả lời SO này: stackoverflow.com/questions/8988824/ cũng như stackoverflow.com/questions/2556190/ này .
slm


Câu trả lời:


45

Trong công cụ POSIX, bạn có thể sử dụng awk:

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

Đừng không sử dụng như một nguồn để tạo mật khẩu hoặc dữ liệu bí mật ví dụ, như với hầu hết awktriển khai, số lượng có thể dễ dàng đoán dựa trên thời gian mà lệnh được chạy.

Với nhiều awktriển khai, lệnh đó chạy hai lần trong cùng một giây thường sẽ cho bạn cùng một đầu ra.


1
+1 .. Như được sử dụng trong tập lệnh để gán đầu ra cho một biến (w / o giới thiệu một ký tự dòng mới và sử dụng phần đệm bằng không cho hai vị trí):x=$(awk -v min=$min_var -v max=$max_var 'BEGIN{srand(); printf("%.2d", int(min+rand()*(max-min+1)))}')
Christopher

Nó dựa trên thời gian? kể từ khi tôi nhận được cùng một giá trị trong 2 lần chạy liên tiếp ...
Shai Alon

@ShaiAlon thời gian hiện tại thường được sử dụng làm giá trị hạt giống mặc định cho srand () vì vậy thông thường, vâng, dựa trên thời gian, hãy xem câu của Stéphane về câu trả lời của anh ấy. Bạn có thể khắc phục điều đó bằng cách thay đổi hạt giống ban đầu thành một số ngẫu nhiên với awk -v min=5 -v max=10 -v seed="$(od -An -N4 -tu4 /dev/urandom)" 'BEGIN{srand(seed+0); print int(min+rand()*(max-min+1))}'. Bạn có thể sử dụng $RANDOMthay vì od ... /dev/randomnhưng sau đó giá trị hạt giống của bạn nằm trong phạm vi tương đối nhỏ từ 0 đến 32767 và do đó, bạn có thể sẽ nhận được sự lặp lại đáng chú ý trong đầu ra của mình theo thời gian.
Ed Morton

141

Bạn có thể thử shuftừ lõi GNU:

shuf -i 1-100 -n 1

Điều này cũng hoạt động với Busybox shuf.
cov

Hoạt động trong raspbian và GitBash quá.
nPcomp

30

ghi

Trên BSD và OSX, bạn có thể sử dụng jot để trả về một số ngẫu nhiên ( -r) duy nhất từ khoảng minđến max, bao gồm.

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

Vấn đề phân phối

Thật không may, phạm vi và phân phối của các số được tạo ngẫu nhiên bị ảnh hưởng bởi thực tế là jot sử dụng số học dấu phẩy động chính xác kép và printf (3) cho định dạng đầu ra, gây ra các vấn đề làm tròn và cắt. Do đó, khoảng minmaxđược tạo ra ít thường xuyên hơn như đã trình bày:

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

Trên OS X 10.11 (El Capitan), điều này dường như đã được sửa:

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

và ...

$ 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

Giải bài toán phân phối

Đối với các phiên bản OS X cũ hơn, may mắn thay, có một số cách giải quyết. Một là sử dụng chuyển đổi số nguyên printf (3). Nhắc nhở duy nhất là khoảng thời gian tối đa bây giờ trở thành max+1. Bằng cách sử dụng định dạng số nguyên, chúng tôi có được phân phối công bằng trên toàn bộ khoảng thời gian:

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

Giải pháp hoàn hảo

Cuối cùng, để có được một con súc sắc công bằng sử dụng cách giải quyết, chúng ta có:

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

Bài tập về nhà thêm

Xem jot (1) để biết chi tiết toán học và định dạng và nhiều ví dụ khác.


15

Các $RANDOMbiến là bình thường không phải là một cách tốt để các giá trị ngẫu nhiên tốt tạo ra. Đầu ra của /dev/[u]randomnhu cầu cũng được chuyển đổi đầu tiên.

Một cách dễ dàng hơn là sử dụng các ngôn ngữ cấp cao hơn, ví dụ như python:

Để tạo biến số nguyên ngẫu nhiên trong khoảng từ 5 đến 10 (5 <= N <= 10), hãy sử dụng

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

Không sử dụng điều này cho các ứng dụng mật mã.


Điều này rất hữu ích. Cảm ơn bạn rất nhiều :) Vì đã ký thường xuyên làm việc với Unix-> Solaris 10, các tiện ích GNU không được tích hợp theo mặc định. Điều này làm việc tuy nhiên.
propatience

11

Bạn có thể nhận được số ngẫu nhiên thông qua urandom

head -200 /dev/urandom | cksum

Đầu ra:

3310670062 52870

Để lấy một phần của số trên.

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

Sau đó, đầu ra là

3310670062


head -200(hoặc POSIX tương đương head -n 100) trả về 200 đầu tiên dòng của /dev/urandom. /dev/urandomkhông phải là tệp văn bản, lệnh đó có thể trả về từ 200 byte (tất cả các 0x0a, LF trong ASCII) thành vô cùng (nếu byte 0xa xảy ra không bao giờ được trả về) nhưng giá trị từ 45k đến 55k là có khả năng nhất. cksum trả về một số 32 bit, do đó, việc lấy hơn 4 byte từ đó là vô nghĩa /dev/urandom.
Stéphane Chazelas

7

Để tạo biến số nguyên ngẫu nhiên trong khoảng từ 5 đến 10 (bao gồm cả hai), hãy sử dụng

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

% làm việc như một toán tử modulo.

Có lẽ có nhiều cách tốt hơn để chuyển đổi biến ngẫu nhiên $RANDOMthành một phạm vi cụ thể. Không sử dụng điều này cho các ứng dụng mã hóa hoặc trong trường hợp bạn cần các biến ngẫu nhiên thực, được phân phối bằng nhau (như cho mô phỏng).


3
Trong nhiều triển khai shell có $ RANDOM (đặc biệt là những cái cũ hơn, đặc biệt là bash), điều đó không phải là rất ngẫu nhiên. Trong hầu hết các shell, số nằm trong khoảng từ 0 đến 65535, do đó, bất kỳ phạm vi nào có chiều rộng không phải là lũy thừa của hai sẽ có sự khác biệt về phân phối xác suất. (trong trường hợp này, các số từ 5 đến 8 sẽ có xác suất 10923/65536, trong khi 9 và 10 sẽ có xác suất 10922/65536). Phạm vi càng rộng, sự khác biệt càng lớn.
Stéphane Chazelas

Xin lỗi, đó là 32767 chứ không phải 65535, vì vậy phép tính ở trên là sai (và nó thực sự tệ hơn).
Stéphane Chazelas

@ StéphaneChazelas Tôi đã nghĩ đến điều này khi tôi viết rằng có nhiều cách tốt hơn ...
jofel

5

# echo $(( $RANDOM % 256 )) sẽ tạo ra một số "ngẫu nhiên" trong khoảng 0-255 theo phương ngữ * sh hiện đại.


Có vẻ tương tự như câu trả lời khác này từ 2 năm trước.
Jeff Schaller

1
Điều này phụ thuộc vào vấn đề chim bồ câu (TL; DR: một số kết quả có nhiều khả năng hơn các vấn đề khác) nếu, thay vì 256, bạn sử dụng một giá trị không chia 32768 như nhau.
toon81

4

Có lẽ UUID(trên Linux) có thể được sử dụng để lấy số ngẫu nhiên

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

Để có được số ngẫu nhiên giữa 70100

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

3
cat /dev/urandom | tr -dc 'a-fA-F0-9' | fold -w 8 | head -n 1

Điều này sẽ tạo ra một số thập lục phân dài 8 chữ số.


1

Để hoàn toàn nằm trong bash và sử dụng biến $ RANDOM nhưng tránh phân phối không đồng đều:

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

Ví dụ này sẽ cung cấp các số ngẫu nhiên từ 20 đến 29.


$rnên được khởi tạo thành 65535 hoặc giá trị cao khác để tránh [: -lt: unary operator expectedlỗi.
LawrenceC

Đã sửa lỗi khởi tạo $ r trước khi kiểm tra vòng lặp. Cảm ơn @LawrenceC!
Hơn Angell

0

Phân phối tốt:

for ((i = 1; i <= 100000; i ++)) tạo ra tiếng vang $ ((RANDOM% (20 - 10 + 1) + 10)); xong | sắp xếp -n | uniq -c

giá trị đếm

9183 10

9109 11

8915 12

9037 13

9100 14

9138 15

9125 16

9261 17

9088 18

8996 19

9048 20

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.