Bash에서 N 중 1 번 명령을 실행하는 방법


15

명령을 무작위로 실행하는 방법을 원합니다 (10 중 1 번). 이를 위해 내장 또는 GNU coreutil이 있습니까?

chance 10 && do_stuff

do_stuff10 번 중 1 번만 어디에서 실행됩니까? 스크립트를 작성할 수는 있지만 상당히 간단한 것 같으며 정의 된 방법이 있는지 궁금합니다.


1
이것은 bash가 합리적 선택을 계속하기 위해 스크립트가 너무 능숙하지 않다는 상당히 좋은 지표입니다. 좀 더 본격적인 프로그래밍 언어, 아마도 Python이나 Ruby와 같은 스크립팅 언어를 고려해야합니다.
알렉산더-복원 모니카

@Alexander 이것은 실제로 스크립트가 아니며 한 줄입니다. 나는 그것을 cron-job에서 무작위로 지금 나에게 알리고 무언가를하기위한 알림으로 사용하고있다
retnikt

답변:


40

에서 ksh, 배쉬, zsh을, 야쉬 또는 비지 박스 sh:

[ "$RANDOM" -lt 3277 ] && do_stuff

RANDOMKorn, Bash, Yash, Z 및 BusyBox 쉘 의 특수 변수는 평가 될 때마다 0에서 32767 사이의 의사 난수 십진 정수 값을 생성하므로 위의 확률은 10 분의 1입니다.

이것을 사용하여 적어도 Bash에서 질문에 설명 된대로 작동하는 함수를 생성 할 수 있습니다.

function chance {
  [[ -z $1 || $1 -le 0 ]] && return 1
  [[ $RANDOM -lt $((32767 / $1 + 1)) ]]
}

인수를 제공하지 않거나 유효하지 않은 인수를 제공하면 1의 결과가 생성되므로 chance && do_stuffnever가되지 않습니다 do_stuff.

이는을 사용하여“1 in n ” 에 대한 일반 공식을 사용 $RANDOM하며, 이는 32768 확률 [[ $RANDOM -lt $((32767 / n + 1)) ]]로 (⎣32767 / n ⎦ + 1)을 제공합니다. n32768의 요소가 아닌 값은 가능한 값 범위에서 고르지 않은 분할로 인해 바이어스 를 유발합니다.


(1/2)이 문제를 다시 방문 할 때 : 부품 수에 상한이 있어야한다는 것은 직관적입니다. 예를 들어 40.000 개의 부품을 가질 수 없습니다. 실제로 실제 한계는 상당히 작습니다. 문제는 정수 나누기가 각 부분의 크기에 대한 근사치라는 것입니다. 두 개의 연속 부품으로 인해 한계 차이 $((32767/parts+1))가 1보다 커야하거나 1의 부품 수가 증가하는 반면 분할 결과 (및 한계)는 동일해야합니다. (계속)
Isaac Isaac

(2/2) (계속) 실제로 사용할 수있는 것보다 많은 수를 설명합니다. 그것에 대한 공식 (32767/n-32767/(n+1))>=1은 ~ 181.5에서 한계를 제공하는 n을 푸는 것입니다. 실제로 부품 수는 문제없이 194 개까지 늘어날 수 있습니다. 그러나 195 개 부품에서 결과 한계는 151 개이며 194 개 부품과 동일한 결과입니다. 그것은 부적절하며 피해야합니다. 요컨대, 부품 수 (n)의 상한은 194 여야합니다. 한계 테스트를 수행 할 수 있습니다.[[ -z $1 || $1 -le 1 || $1 -ge 194 ]] && return 1
Isaac

25

비표준 솔루션 :

[ $(date +%1N) == 1 ] && do_stuff

현재 시간의 마지막 자릿수가 나노초인지 확인하십시오!


대단해.
Eric Duminil 19 :

2
[ $(date +%1N) == 1 ] && do_stuff규칙적인 간격으로 호출 이 발생하지 않도록 해야합니다. 그렇지 않으면 임의성이 손상됩니다. while true; do [ $(date +1%N) == 1 ] && sleep 1; done추상적 인 반례로 생각하십시오 . 그럼에도 불구하고, 나노초를 가지고 노는 아이디어는 정말 좋습니다. 그래서 나는 그것을 사용할 것이라고 생각합니다. 따라서 +1
XavierStuvw

3
@XavierStuvw 코드가 초를 확인하면 요점이 있다고 생각합니다. 그러나 나노초? 정말 무작위로 나타납니다.
Eric Duminil

9
@EricDuminil : 불행히도 : 1) 시스템 시계는 실제 나노초 분해능을 제공하도록 계약 상 의무가 없습니다 (가장 가까운 시간으로 반올림 할 수 있음 clock_getres()). (클럭이 올바른 경우에도 바이어스가 발생 함), 3) 임의의 값을 얻는 지원되는 방법은 (보통) /dev/urandom의 값을 읽 거나 검사하는 것입니다 $RANDOM.
Kevin

1
@ 케빈 : 댓글 주셔서 감사합니다.
Eric Duminil 19

21

사용에 대한 대안 $RANDOM은 다음 shuf명령입니다.

[[ $(shuf -i 1-10 -n 1) == 1 ]] && do_stuff

일을 할 것입니다. 예를 들어 파일에서 라인을 무작위로 선택할 때도 유용합니다. 음악 재생 목록 용.


1
그 명령을 몰랐다. 아주 좋아요!
Eisenknurr

12

첫 번째 답변을 개선하고 달성하려는 목표를 훨씬 더 명확하게 만듭니다.

[ $(( $RANDOM % 10 )) == 0 ] && echo "You win" || echo "You lose"

1
$RANDOM % 10$RANDOM정확히 10 개의 다른 값의 배수 (일반적으로 이진 컴퓨터에서는 발생하지 않음)를 생성 하지 않는 한 편향이 있습니다.
phuclv

1
@phuclv 그렇습니다 "$RANDOM" -lt $((32767 / n + 1)).
Eisenknurr

예, 1-in-10의 경우 0.1 대신 바이어스가 0.100006104입니다 (0에 대해 검사시).
Stephen Kitt

1

무작위 또는 주기성을 원하는지 확실하지 않습니다 ... 주기성을 위해 :

for i in `seq 1 10 100`; do echo $i;done
1
11
21
31
41
51
61
71
81
91

예를 들어 위의 "$ RANDOM"트릭과 혼합하여 더 혼란스러운 것을 만들 수 있습니다.

i의 경우 seq 1 1000 $RANDOM; 메아리 $ i; 완료

HTH :-)

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