Quiero una forma de ejecutar un comando al azar, digamos 1 de cada 10 veces. ¿Hay un coreutil incorporado o GNU para hacer esto, idealmente algo como:
chance 10 && do_stuff
donde do_stuff
solo se ejecuta 1 de cada 10 veces? Sé que podría escribir un guión, pero parece algo bastante simple y me preguntaba si hay una forma definida.
Respuestas:
En
ksh
, Bash, Zsh, Yash u BusyBoxsh
:La
RANDOM
variable especial de los shells Korn, Bash, Yash, Z y BusyBox produce un valor entero decimal pseudoaleatorio entre 0 y 32767 cada vez que se evalúa, por lo que lo anterior da (cerca de) una posibilidad de uno en diez.Puede usar esto para producir una función que se comporte como se describe en su pregunta, al menos en Bash:
Olvidar proporcionar un argumento, o proporcionar un argumento no válido, producirá un resultado de 1, por
chance && do_stuff
lo que nunca lo harádo_stuff
.Esto usa la fórmula general para "1 en n " usando
$RANDOM
, que es[[ $RANDOM -lt $((32767 / n + 1)) ]]
, dando un (⎣32767 / n ⎦ + 1) en 32768 posibilidades. Los valores de losn
cuales no son factores de 32768 introducen un sesgo debido a la división desigual en el rango de valores posibles.fuente
$((32767/parts+1))
den como resultado que una diferencia del límite sea mayor que 1 o corremos el riesgo de que el número de partes aumente en 1 mientras el resultado de la división (y, por lo tanto, el límite) sea el mismo. (cont.)(32767/n-32767/(n+1))>=1
resolver para n que da un límite de ~ 181.5. De hecho, el número de piezas podría correr hasta 194 sin problemas. Pero con 195 partes, el límite resultante es 151, el mismo resultado que con 194 partes. Eso es incongruente y debe evitarse. En resumen, el límite superior para el número de partes (n), debería ser 194. Podría hacer las pruebas de límite:[[ -z $1 || $1 -le 1 || $1 -ge 194 ]] && return 1
Solución no estándar:
[ $(date +%1N) == 1 ] && do_stuff
¡Compruebe si el último dígito de la hora actual en nanosegundos es 1!
fuente
[ $(date +%1N) == 1 ] && do_stuff
no se produce a intervalos regulares, de lo contrario, la aleatoriedad se echa a perder. Piensewhile true; do [ $(date +1%N) == 1 ] && sleep 1; done
en un contraejemplo abstracto. Sin embargo, la idea de jugar con los nanosegundos es realmente buena, creo que laclock_getres()
), 2) No se prohíbe al programador, por ejemplo, comenzar siempre un intervalo de tiempo en un límite de 100 nanosegundos (lo que introduciría un sesgo incluso si el reloj es correcto), 3) La forma compatible de obtener valores aleatorios es (generalmente) leer/dev/urandom
o inspeccionar el valor de$RANDOM
.Una alternativa al uso
$RANDOM
es elshuf
comando:Hará el trabajo. También es útil para seleccionar al azar líneas de un archivo, por ejemplo. para una lista de reproducción de música.
fuente
Mejorando la primera respuesta y haciendo mucho más obvio lo que está tratando de lograr:
fuente
$RANDOM % 10
tendrá un sesgo, a menos que la$RANDOM
produce exactamente un múltiplo de 10 valores diferentes (que generalmente no ocurre en un ordenador binario)"$RANDOM" -lt $((32767 / n + 1))
.No estoy seguro si quieres aleatoriedad o periodicidad ... Para periodicidad:
Puedes mezclarlo con el truco "$ RANDOM" anterior para producir algo más caótico, por ejemplo:
porque yo en
seq 1 1000 $RANDOM
; do echo $ i; hechoHTH :-)
fuente