Vous ne devez jamais utiliser cat
avec /dev/urandom
. Vous ne devez pas non plus utiliser d'utilitaires conçus pour les fichiers texte.
/dev/urandom
est un flux continu de données aléatoires. Il ne produira jamais de fin de fichier. Les lectures tamponnées rempliront le tampon de lecture, donc même si vous dirigez la sortie de cat
dans un autre programme, la lecture ne sera pas terminée tant que le tube ne sera pas fermé.
Rien de tout cela ne serait autre chose qu'inefficace, sauf que lorsque vous lisez /dev/urandom
, vous utilisez de l'entropie (aléatoire), qui est une ressource précieuse. Une fois l'entropie épuisée, /dev/urandom
La sortie sera moins aléatoire, ce qui va à l'encontre de l'objectif. (Plus d'entropie sera collectée, mais cela prend un certain temps pour s'accumuler.)
Tout cela double pour /dev/random
, car lorsqu'il manque d'entropie, il se bloque généralement. (Sauf sur les OS qui font /dev/random
un synonyme de /dev/urandom
.)
Par conséquent, vous devez toujours lire exactement la quantité de données aléatoires dont vous avez besoin, et pas plus.
Apparemment, vous visez 24 caractères alphanumériques. Il y a 62 caractères alphanumériques possibles; cela simplifierait grandement les choses si vous étiez prêt à autoriser deux autres caractères à porter le total à 64. Dans ce cas, vous pourriez produire 24 caractères en extrayant 18 octets de caractère aléatoire et en les faisant passer par un encodeur base64. Pour extraire une quantité précise de données, utilisez dd
, qui est conçu dans le but :
dd bs=18 count=1 if=/dev/urandom | base64 | tr +/ _.
(Le tr
à la fin traduit les deux caractères non alphanumériques produits par base64
en deux caractères différents qui sont plus conviviaux pour les noms de fichiers. Juste une suggestion.)
Si vous êtes déterminé à utiliser précisément des caractères alphanumériques, vous pouvez utiliser une stratégie de rejet similaire à celle que vous utilisez actuellement, mais basée sur ce qui précède. Malheureusement, il n'est pas possible de prédire exactement la quantité d'entrée dont vous aurez besoin dans ce cas, donc l'approche la plus simple est de lire un peu plus et de réessayer dans les rares cas où vous n'en obtenez pas assez :
# Here we produce 28 characters each time
until s=$(dd bs=21 count=1 if=/dev/urandom |
LC_ALL=C tr -cd A-Za-z0-9)
((${#s} >= 24)); do :; done
# When the loop ends we have at least 24 characters; truncate
s=${s:0:24}
Si vous n'avez pas bash, vous pouvez remplacer ((${#s} >= 24))
avec [ ${#s} -ge 24 ]
et s=${s:0:24}
avec s=$(printf %.24s $s)
Mais si vous essayez simplement de générer de bons noms de fichiers aléatoires, vous devez utiliser mktemp
, qui vous permet de spécifier un squelette pour les noms, et vérifie également que le nom généré n'est pas déjà présent. Voir man mktemp
.
En fait cat /dev/urandom
ne se termine jamais tout seul. Mais quand head -1
lit la première ligne, il sort, fermant ainsi stdin et fermant un tube. Le système d'exploitation génère SIGPIPE
à fold
est également des sorties, et ainsi de suite, donc cat /dev/urandom
se termine finalement.
Dans votre cas, quelque chose bloque SIGPIPE
, c'est-à-dire que trap peut faire cela :
$ trap '' PIPE
$ cat /dev/urandom | LC_ALL=C tr -dc 'a-zA-Z0-9' | fold -w 24 | head -n 1
7FazO6mnsIow3ylkvEHB55jE
(hungs)
Essayez de le réactiver dans le sous-shell :
( trap - PIPE ; cat /dev/urandom | LC_ALL=C tr -dc 'a-zA-Z0-9' | fold -w 24 | head -n 1 )