Nunca debes usar cat
con /dev/urandom
. Tampoco debe usar ninguna utilidad que esté diseñada para archivos de texto.
/dev/urandom
es un flujo continuo de datos aleatorios. Nunca producirá un final de archivo. Las lecturas almacenadas en búfer llenarán el búfer de lectura, por lo que incluso si está canalizando la salida de cat
en algún otro programa, la lectura no terminará hasta que se cierre la tubería.
Nada de eso sería otra cosa que ineficiente, excepto que cuando lees /dev/urandom
, estás consumiendo entropía (aleatoriedad), que es un recurso precioso. Una vez que se agota la entropía, /dev/urandom
La salida será menos aleatoria, lo que anula el propósito. (Se recolectará más entropía, pero lleva un tiempo acumularse).
Todo esto se duplica para /dev/random
, porque cuando se queda sin entropía, suele bloquearse. (Excepto en los sistemas operativos que hacen /dev/random
un sinónimo de /dev/urandom
.)
En consecuencia, siempre debe leer exactamente la cantidad de datos aleatorios que necesita, y no más.
Aparentemente, estás apuntando a 24 caracteres alfanuméricos. Hay 62 caracteres alfanuméricos posibles; simplificaría mucho las cosas si estuviera dispuesto a permitir que otros dos caracteres llevaran el total a 64. En ese caso, podría producir 24 caracteres extrayendo 18 bytes de aleatoriedad y pasándolos a través de un codificador base64. Para extraer una cantidad precisa de datos, use dd
, que está diseñado para el propósito:
dd bs=18 count=1 if=/dev/urandom | base64 | tr +/ _.
(El tr
al final traduce los dos caracteres no alfanuméricos producidos por base64
en dos caracteres diferentes que son más amigables con los nombres de archivo. Solo una sugerencia.)
Si está decidido a usar caracteres alfanuméricos precisos, podría usar una estrategia de rechazo similar a la que está usando actualmente, pero basada en lo anterior. Desafortunadamente, no es posible predecir exactamente cuánta entrada necesitará en este caso, por lo que el enfoque más simple es leer un poco más y volver a intentarlo en el raro caso de que no obtenga suficiente:
# 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 no tiene bash, puede reemplazar ((${#s} >= 24))
con [ ${#s} -ge 24 ]
y s=${s:0:24}
con s=$(printf %.24s $s)
Pero si solo está tratando de generar buenos nombres de archivo aleatorios, debe usar mktemp
, que le permite especificar un esqueleto para los nombres y también verifica que el nombre generado no esté ya presente. Ver man mktemp
.
En realidad cat /dev/urandom
nunca termina por sí solo. Pero cuando head -1
lee la primera línea, sale, cerrando así stdin y cerrando una tubería. OS plantea SIGPIPE
a fold
también sale, y así sucesivamente, por lo que cat /dev/urandom
termina eventualmente.
En tu caso, algo bloquea SIGPIPE
, es decir, trap puede hacer eso:
$ trap '' PIPE
$ cat /dev/urandom | LC_ALL=C tr -dc 'a-zA-Z0-9' | fold -w 24 | head -n 1
7FazO6mnsIow3ylkvEHB55jE
(hungs)
Intente volver a habilitarlo en subshell:
( trap - PIPE ; cat /dev/urandom | LC_ALL=C tr -dc 'a-zA-Z0-9' | fold -w 24 | head -n 1 )