특정 범위에서 난수 생성


84

인터넷 검색을 한 후 쉘 명령을 사용하여 특정 범위에 포함 된 임의의 십진 정수를 생성하는 간단한 방법을 찾을 수 없었습니다. 최소와 최대 사이입니다.

나는 읽어 /dev/random, /dev/urandom그리고 $RANDOM,이 중에 내가 필요로 무엇을 할 수 없다.

다른 유용한 명령이나 이전 데이터를 사용하는 방법이 있습니까?




답변:


45

POSIX toolchest에서 다음을 사용할 수 있습니다 awk.

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

마십시오 하지 대부분과 마찬가지로, 암호 또는 예를 들어 비밀 데이터를 생성하기 위해 소스로 저를 사용하여 awk구현, 숫자를 쉽게 실행 된 명령 시간을 기준으로 추측 할 수있다.

많은 awk구현에서, 해당 명령은 동일한 초 내에 두 번 실행되어 일반적으로 동일한 출력을 제공합니다.


1
+1 .. 변수에 출력을 할당하기 위해 스크립트에서 사용되는 경우 (개행 문자를 도입하지 않고 두 위치에 제로 패딩을 사용하지 않음)x=$(awk -v min=$min_var -v max=$max_var 'BEGIN{srand(); printf("%.2d", int(min+rand()*(max-min+1)))}')
Christopher

시간을 기준으로합니까? 연속 2 회 연속으로 같은 가치를 얻었으므로 ...
Shai Alon

@ShaiAlon 현재 시간은 종종 srand ()의 기본 시드 값으로 사용되므로 일반적으로 시간을 기준으로합니다 .Stéphane의 답변에 대한 문장을 참조하십시오. 를 사용하여 초기 시드를 임의의 숫자로 변경하면 문제를 해결할 수 있습니다 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))}'. $RANDOM대신에 사용할 수 od ... /dev/random있지만 시드 값의 범위는 0에서 32767 사이로 비교적 작으므로 시간이 지남에 따라 출력에서 ​​눈에 띄게 반복 될 수 있습니다.
Ed Morton

141

shufGNU coreutils에서 시도해 볼 수 있습니다 :

shuf -i 1-100 -n 1

이것은 Busybox에서도 작동합니다 shuf.
cov

라즈 비안과 GitBash에서도 작동합니다.
nPcomp

30

조금

BSD와 OSX에서 당신은 사용할 수 조금도 하나의 임의 (돌아 -r간격에서) 수 minmax포함.

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

배포 문제

불행하게도, 무작위로 생성 된 숫자의 범위와 분포는 jot이 내부에서 배정도 부동 소수점 산술을 사용하고 출력 형식에 printf (3)를 사용하여 반올림 및 잘림 문제를 유발한다는 사실에 영향을받습니다. 따라서 다음과 같이 간격 min과 간격 max이 덜 생성됩니다.

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

OS X 10.11 (El Capitan)에서는 다음과 같이 수정되었습니다.

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

과...

$ 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

분포 문제 해결

이전 버전의 OS X의 경우 다행스럽게도 몇 가지 해결 방법이 있습니다. 하나는 printf (3) 정수 변환을 사용하는 것입니다. 유일한 경고는 이제 최대 간격이됩니다 max+1. 정수 형식을 사용하면 전체 간격에 걸쳐 공정한 분포를 얻습니다.

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

완벽한 솔루션

마지막으로, 해결 방법을 사용하여 주사위를 공정하게 굴리려면 다음과 같은 이점이 있습니다.

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

추가 숙제

까다로운 수학 및 서식 세부 정보 및 더 많은 예제는 jot (1) 을 참조하십시오 .


15

$RANDOM변수는 일반적으로 생성 좋은 임의의 값에 좋은 방법이 아니다. 출력 /dev/[u]random도 먼저 변환해야합니다.

더 쉬운 방법은 파이썬과 같은 고급 언어를 사용하는 것입니다.

5와 10 사이의 임의의 정수 변수를 생성하려면 (5 <= N <= 10)

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

암호화 응용 프로그램에는 이것을 사용하지 마십시오.


이것은 유용했습니다. 대단히 감사합니다 :) 서명이 자주 Unix-> Solaris 10과 함께 작동했듯이 GNU 유틸리티는 기본적으로 통합되어 있지 않습니다. 그러나 이것은 효과가있었습니다.
Propatence

11

당신은 난수를 통해 얻을 수 있습니다 urandom

head -200 /dev/urandom | cksum

산출:

3310670062 52870

위 숫자의 한 부분을 검색합니다.

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

그런 다음 출력은

3310670062


head -200(또는 해당 POSIX 해당 head -n 100)는의 첫 200 을 반환합니다 /dev/urandom. /dev/urandom텍스트 파일이 아닌 경우 해당 명령은 200 바이트 (모든 0x0a 1, ASCII의 LF)에서 무한대로 (0xa 바이트가 반환되지 않는 경우) 반환 할 수 있지만 45k와 55k 사이의 값이 가장 가능성이 높습니다. cksum은 32 비트 숫자를 반환하므로에서 4 바이트 이상을 가져 오는 것은 의미가 없습니다 /dev/urandom.
Stéphane Chazelas

7

5와 10 사이의 임의의 정수 변수를 생성하려면 (둘 다 포함)

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

% 모듈로 연산자로 작동합니다.

랜덤 변수 $RANDOM를 특정 범위 로 변환하는 더 좋은 방법이있을 것입니다 . 암호화 응용 프로그램이나 시뮬레이션에 사용되는 등분 산 된 실제 랜덤 변수가 필요한 경우에는 이것을 사용하지 마십시오.


3
$ RANDOM (특히 오래된 것들, 특히 bash)이있는 많은 쉘 구현에서는 그다지 무작위가 아닙니다. 대부분의 셸에서 숫자는 0에서 65535 사이이므로 너비가 2의 거듭 제곱이 아닌 모든 범위는 확률 분포 불일치를 갖습니다. (이 경우 5에서 8까지의 숫자는 10923/65536의 확률을 가지지 만 9와 10에서는 10922/65536의 확률을 가질 것입니다). 범위가 넓을수록 불일치가 커집니다.
Stéphane Chazelas

죄송합니다, 65535가 아닌 32767이므로, 위의 계산이 잘못되었습니다 (실제로는 더 나쁩니다).
Stéphane Chazelas

@ StéphaneChazelas 더 좋은 방법이 있다고 썼는데 이것을 염두에 두었습니다.
jofel

5

# echo $(( $RANDOM % 256 )) 현대 * sh 방언에서 0-255 사이의 "무작위"숫자를 생성합니다.


2 년 전의 다른 대답 과 비슷합니다 .
Jeff Schaller

1
이 적용됩니다 비둘기 문제 (TL; DR : 어떤 결과가 다른 사람보다 더 높습니다) 대신에 256의, 경우, 당신은 똑같이 32768를 분할하지 않는 값을 사용합니다.
toon81

4

어쩌면 UUID(Linux의 경우)를 사용하여 난수를 검색 할 수 있습니다

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

70와 사이의 난수를 얻으려면100

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

이렇게하면 8 자리 길이의 16 진수가 생성됩니다.


1

bash 내에 완전히 머무르고 $ RANDOM 변수를 사용하지만 고르지 않은 분포는 피하십시오.

#!/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 ))

이 예는 20에서 29 사이의 난수를 제공합니다.


$r[: -lt: unary operator expected오류 를 피하려면 65535 또는 기타 높은 값으로 초기화해야합니다 .
LawrenceC

루프 테스트 전에 $ r 초기화를 수정했습니다. 감사합니다 @LawrenceC!
Angell보다

0

배포가 좋습니다 :

for ((i = 1; i <= 100000; i ++)) do echo $ ((RANDOM % (20-10 + 1) + 10)); 완료 | 정렬 -n | 유니크 -c

카운트 값

9183 10

9109 11

8915 12

9037 13

9100 14

9138 15

9125 16

9261 17

9088 18

8996 19

9048 20

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.