Mon script produit la même sortie lors de l'utilisation de $ RANDOM

8

J'essaie d'imprimer un nmot de lettre aléatoire , où j'entre à npartir de la ligne de commande elle-même, mais pour une raison quelconque, mon script me donne la même réponse à chaque fois lorsque j'utilise la même valeur pour n.

#!/bin/bash                                                                                                                                       
num=$1
egrep "^.{$num}$" /usr/share/dict/words | head -n $RANDOM| tail -n 1

J'appelle mon script comme:

$ bash var3.sh 5
étude             # always the same output when using 5 

$ bash var3.sh 3
zoo               # always the same output when using 3

var3.shest le nom de mon script et 5 est la longueur du mot que je veux imprimer au hasard.

Comment puis-je faire imprimer un mot vraiment aléatoire?

Karan Singh
la source
3
$RANDOMest très probablement supérieur au nombre de mots à n lettres pour la plupart des valeurs de n (95,7% du temps pour n = 3 pour moi).
Michael Homer
Cherchez-vous à imprimer un mot au hasard complètement, même si ce n'est pas un mot ou à l'imprimer au hasard à partir du dict?
iZodiac
Si votre tâche est liée à la sécurité (par exemple pour créer un mot de passe), vous devez utiliser un outil conçu pour cette tâche. Sinon, il est possible d'utiliser shufou sort -Rcomme suggéré dans les réponses. Vous pouvez également utiliser $RANDOM, mais d'une manière plus avancée. Tous ces outils produisent des résultats prévisibles (ils ne sont pas vraiment aléatoires), mais ils sont rapides et suffisamment bons pour de nombreuses applications.
sudodus
1
Peut-être qu'ils utilisent cette méthode (référence XKCD obligatoire)
molnarm

Réponses:

20

Ce n'est pas le cas. Mais $ RANDOM renvoie de grands nombres (entre 0 et 32767) qui, en particulier pour les mots de longueur limitée, montrent le même résultat, car la headpartie renvoie probablement tous les résultats du grep (pour 3, il n'y a que 819 correspondances dans mon /usr/share/dict/words).

La meilleure solution pourrait être de mélanger les résultats:

egrep "^.{$num}$" /usr/share/dict/words | sort -R | tail -n 1

-Rsignifie --random-sort(une sortextension GNU ).

Jakub Lucký
la source
16
Pourquoi tail? Cela avait du sens dans le script OP, mais puisque vous mélangez, vous pouvez également utiliser head, et sortdevrait ensuite être en mesure de détecter le tuyau cassé et de ne pas déranger le reste des lignes.
Peter Taylor
@PeterTaylor est probablement un bon conseil. Utiliser la queue est juste une de mes habitudes ... Au final, je préférerais probablement encore plus la shuf -n1, qui est une pipe de moins ...
Jakub Lucký
19

Une méthode simple pour imprimer un arbitraire num -lettre mot utilisations shuf:

egrep "^.{$num}$" /usr/share/dict | shuf -n1

La shufcommande génère une permutation aléatoire de l'entrée et le -n1drapeau lui indique de ne sortir que le premier élément de ce résultat.

Renard
la source
3
ou grep -Ex ".{$num}". Ou awk 'length == n' n="$num"'.
Stéphane Chazelas
5

Comme d'autres l'ont souligné, le principal problème avec votre code est que le $RANDOMplus souvent, il va y avoir une valeur beaucoup plus grande que le nombre de mots d'une certaine longueur.

En utilisant awkuniquement:

$ awk -v len="$num" 'length == len { word[i++]=$0 }
                     END { print word[int(i*rand())] }' /usr/share/dict/words
Bosniac

Le programme lit dans toutes les lignes du fichier donné qui sont d'une certaine longueur. Ceux-ci sont stockés dans le tableau words.

À la fin, un élément aléatoire de ce tableau est sélectionné et imprimé.

Kusalananda
la source