2011-10-04 3 views
4

Comment générer des nombres aléatoires en utilisant AShell (bash restreint)? J'utilise un binaire BusyBox sur l'appareil qui n'a pas od ou $RANDOM. Mon appareil a /dev/urandom et /dev/random.Comment générer des nombres aléatoires dans le shell BusyBox

+0

Est-ce une faute de frappe? "Vous utilisez busybox et vous n'avez donc pas '' od '"? Busybox _includes_ 'od' (et ça fait longtemps). Appelez simplement 'busybox od' directement si le _link_' od -> busybox' n'existe pas. –

+0

@FrankH. Presque tous les composants de BusyBox sont facultatifs, y compris 'od' et' $ RANDOM'. – Gilles

Répondre

6

$RANDOM et od sont des fonctionnalités optionnelles dans BusyBox, je suppose étant donné votre question qu'ils ne sont pas inclus dans votre binaire. Vous mentionnez dans un commentaire que /dev/urandom est présent, c'est bien, cela signifie que ce que vous devez faire est d'en récupérer des octets sous une forme utilisable, et pas le problème beaucoup plus difficile de l'implémentation d'un générateur de nombres aléatoires. Notez que vous devez utiliser /dev/urandom et non /dev/random, voir Is a rand from /dev/urandom secure for a login key?.

Si vous avez tr ou sed, vous pouvez lire les octets de /dev/urandom et ignorer tout octet qui n'est pas un caractère souhaitable. Vous aurez également besoin d'un moyen d'extraire un nombre fixe d'octets d'un flux: soit head -c (nécessitant FEATURE_FANCY_HEAD pour être activé) ou dd (nécessitant dd pour être compilé). Plus vous rejetez d'octets, plus cette méthode sera lente. Pourtant, la génération d'octets aléatoires est généralement plutôt rapide en comparaison avec le bifurcation et l'exécution de binaires externes, donc en jeter un grand nombre ne fera pas trop mal. Par exemple, l'extrait suivant produira un nombre aléatoire entre 0 et 65535:

n=65536 
while [ $n -ge 65536 ]; do 
    n=1$(</dev/urandom tr -dc 0-9 | dd bs=5 count=1 2>/dev/null) 
    n=$((n-100000)) 
done 

Notez qu'en raison de mise en mémoire tampon, tr va traiter assez peu plus d'octets que ce dd va finir par la tenue. BusyBox tr lit un tampon (au moins 512 octets) à la fois, et vide son tampon de sortie chaque fois que le tampon d'entrée est entièrement traité, donc la commande ci-dessus lira toujours au moins 512 octets de /dev/urandom (et très rarement plus depuis la prise attendue à partir de 512 octets d'entrée est 20 chiffres décimaux).

Si vous avez besoin d'une chaîne imprimable unique, tout jeter des caractères non-ASCII, et peut-être certains caractères de ponctuation ennuyeux:

nonce=$(</dev/urandom tr -dc A-Za-z0-9-_ | head -c 22) 

Dans cette situation, je voudrais sérieusement envisager d'écrire un petit programme dédié C . En voici un qui lit quatre octets et sort le nombre décimal correspondant. Il ne repose sur aucune autre fonction de libc que les wrappers pour les appels système read et write, donc vous pouvez obtenir un très petit binaire. La prise en charge d'une variable variable transmise sous la forme d'un nombre décimal entier sur la ligne de commande est conservée en tant qu'exercice; cela vous coûtera des centaines d'octets de code (ce qui ne vous inquiète pas si votre cible est assez grande pour faire tourner Linux).

#include <stddef.h> 
#include <unistd.h> 
int main() { 
    int n; 
    unsigned long x = 0; 
    unsigned char buf[4]; 
    char dec[11]; /* Must fit 256^sizeof(buf) in decimal plus one byte */ 
    char *start = dec + sizeof(dec) - 1; 
    n = read(0, buf, sizeof(buf)); 
    if (n < (int)sizeof(buf)) return 1; 
    for (n = 0; n < (int)sizeof(buf); n++) x = (x << 8 | buf[n]); 
    *start = '\n'; 
    if (x == 0) *--start = '0'; 
    else while (x != 0) { 
     --start; 
     *start = '0' + (x % 10); 
     x = x/10; 
    } 
    while (n = write(1, start, dec + sizeof(dec) - start), 
      n > 0 && n < dec + sizeof(dec) - start) { 
     start += n; 
    } 
    return n < 0; 
} 
+0

J'ai amélioré votre premier extrait et le mettre dans une réponse séparée ci-dessous, car les commentaires ne semblent pas supporter les blocs de code. – escitalopram

+0

@escitalopram Merci pour les corrections. Pour référence future, vous êtes [bienvenue et même encouragé à éditer les messages pour corriger les erreurs mineures] (http://stackoverflow.com/help/editing) (attention, certains [si] utilisateurs le détestent lorsque vous modifiez leur code brisé - Je ne suis pas un de ceux-ci cependant. – Gilles

1

/dev/random ou/dev/urandom sont susceptibles d'être présents.

Une autre option consiste à écrire un petit programme C qui appelle srand(), puis rand().

+0

oui/dev/urandom et/dev/random sont présents, mais comment les utiliser sans od. Je peux lire ensuite en utilisant dd. Alors qu'est-ce que je fais? – abc

+1

'/ dev/random' contient des données aléatoires (caractères de 256 bits). 'head -c N/dev/random' vous donne' N' octets de données aléatoires. – Dennis

1
</dev/urandom sed 's/[^[:digit:]]\+//g' | head -c10 
+0

Cela donne parfois des espaces dans le nombre généré, comme "6 60 09807" ou "076 2 15". –

1

I Tried premier extrait de Gilles avec BusyBox 1,22.1 et moi avons des patchs, qui ne cadrait pas avec un commentaire:

while [ $n -gt 65535 ]; do 
    n=$(</dev/urandom tr -dc 0-9 | dd bs=5 count=1 2>/dev/null | sed -e 's/^0\+//') 
done 
  1. La condition de la boucle doit vérifier supérieure à la valeur maximale, sinon il y aura 0 exécutions.
  2. Je réduit au silence stderr de dd
  3. zéros, a été enlevé ce qui pourrait conduire à des surprises dans des contextes où interprétés comme octal (par exemple $(()))
1

Hexdump et dc sont tous deux disponibles avec busybox. Utilisez/dev/urandom pour la plupart aléatoire ou/dev/random pour mieux aléatoire. Chacune de ces options est meilleure que $ RANDOM et sont toutes deux plus rapides que la recherche de caractères imprimables en boucle.

32 bits nombre aléatoire décimales:

CNT=4 
RND=$(dc 10 o 0x$(hexdump -e '"%02x" '$CNT' ""' -n $CNT /dev/random) p) 

hex nombre aléatoire 24 bits:

CNT=3 
RND=0x$(hexdump -e '"%02x" '$CNT' ""' -n $CNT /dev/random) 

Pour obtenir de plus petits nombres, changer le format de la chaîne de format hexdump et le nombre d'octets cet hexdump lit.

Questions connexes