Generar un nombre de archivo aleatorio en unix shell


Me gustaría generar un nombre de archivo aleatorio en unix shell (por ejemplo tcshell). El nombre del archivo debe consistir en 32 letras hexadecimales aleatorias, por ejemplo:

c7fdfc8f409c548a10a0a89a791417c5

(a lo que añadiré lo que sea necesario). El punto es poder hacerlo solo en shell sin recurrir a un programa.

Author: R S, 2010-05-08

12 answers

Asumiendo que estás en un linux, lo siguiente debería funcionar:

cat /dev/urandom | tr -cd 'a-f0-9' | head -c 32

Esto solo es pseudo-aleatorio si su sistema tiene poca entropía, pero (en linux) está garantizado que terminará. Si necesita datos realmente aleatorios, cat /dev/random en lugar de /dev/urandom. Este cambio hará que su código se bloquee hasta que haya suficiente entropía disponible para producir una salida verdaderamente aleatoria, por lo que podría ralentizar su código. Para la mayoría de los usos, la salida de /dev/urandom es suficientemente aleatoria.

Si está en OS X u otro BSD, necesidad de modificarlo a lo siguiente:

cat /dev/urandom | env LC_CTYPE=C tr -cd 'a-f0-9' | head -c 32
 107
Author: fmark,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2010-05-10 02:29:57

Por qué no usar el comando unix mktemp:

$ TMPFILE=`mktemp tmp.XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX` &&  echo $TMPFILE
tmp.MnxEsPDsNUjrzDIiPhnWZKmlAXAO8983
 37
Author: Oleg Razgulyaev,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2010-05-08 11:28:20

Un comando, sin tubería, sin bucle:

hexdump -n 16 -v -e '/1 "%02X"' -e '/16 "\n"' /dev/urandom

Si no necesita la nueva línea, por ejemplo cuando la está usando en una variable:

hexdump -n 16 -v -e '/1 "%02X"' /dev/urandom

Usando "16" genera 32 dígitos hexadecimales.

 17
Author: Dennis Williamson,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-11-08 17:50:38

Probado en zsh, debería funcionar con cualquier shell compatible con BASH!

#!/bin/zsh

SUM=`md5sum <<EOF
$RANDOM
EOF`

FN=`echo $SUM | awk '// { print $1 }'`

echo "Your new filename: $FN"

Ejemplo:

$ zsh ranhash.sh
Your new filename: 2485938240bf200c26bb356bbbb0fa32
$ zsh ranhash.sh
Your new filename: ad25cb21bea35eba879bf3fc12581cc9
 5
Author: LukeN,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2010-05-08 11:15:07

Como probablemente notaste en cada una de las respuestas, generalmente tienes para "recurrir a un programa".

Sin embargo, sin usar ningún ejecutable externo , en Bash y ksh:

string=''; for i in {0..31}; do string+=$(printf "%x" $(($RANDOM%16)) ); done; echo $string

En zsh:

string=''; for i in {0..31}; do string+=$(printf "%x" $(($RANDOM%16)) ); dummy=$RANDOM; done; echo $string

Cambie la x minúscula en la cadena de formato a una X mayúscula para hacer que los caracteres hexadecimales alfabéticos sean mayúsculos.

Aquí hay otra forma de hacerlo en Bash pero sin un bucle explícito:

printf -v string '%X' $(printf '%.2s ' $((RANDOM%16))' '{00..31})

En el siguiente, "primero "y" segundo " printf se refiere al orden en el que se ejecutan en lugar del orden en el que aparecen en la línea.

Esta técnica utiliza la expansión de llaves para producir una lista de 32 números aleatorios mod 16 cada uno seguido de un espacio y uno de los números en el rango en llaves seguido de otro espacio (por ejemplo, 11 00). Para cada elemento de esa lista, el primer printf elimina todos los caracteres excepto los dos primeros utilizando su cadena de formato (%.2) dejando un solo dígito seguido de un espacio de cada uno o dos dígitos. El espacio en la cadena de formato garantiza que haya al menos un espacio entre cada número de salida.

La sustitución de comandos que contiene el primer printf no se cita para que se realice la división de palabras y cada número vaya al segundo printf como un argumento separado. Allí, los números se convierten a hexadecimal mediante la cadena de formato %X y se anexan entre sí sin espacios (ya que no hay ninguno en la cadena de formato) y el resultado es almacenado en la variable llamada string.

Cuando printf recibe más argumentos que su cadena de formato, el formato se aplica a cada argumento a su vez hasta que se consumen todos. Si hay menos argumentos, la cadena de formato no coincidente (porción) se ignora, pero eso no se aplica en este caso.

Lo probé en Bash 3.2, 4.4 y 5.0-alfa. Pero no funciona en zsh (5.2) o ksh (93u+) porque RANDOM solo se evalúa una vez en la expansión de llaves en esos shell.

Tenga en cuenta que debido al uso del operador mod en un valor que varía de 0 a 32767, la distribución de dígitos utilizando los fragmentos podría ser sesgada (sin mencionar el hecho de que los números son pseudo aleatorios en primer lugar). Sin embargo, ya que estamos usando mod 16 y 32768 es divisible por 16, eso no será un problema aquí.

En cualquier caso, la forma correcta de hacerlo es usando mktemp como en La respuesta de Oleg Razgulyaev.

 5
Author: Dennis Williamson,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-09-04 17:19:24

Esta respuesta es muy similar a fmarks, por lo que realmente no puedo tomar el crédito por ello, pero me pareció que las combinaciones de comandos cat y tr bastante lento, y me encontré con esta versión un poco más rápido. Necesitas hexdump.

hexdump -e '/1 "%02x"' -n32 < /dev/urandom
 3
Author: srclosson,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-07-21 19:49:42

Otra manera[tm].

R=$(echo $RANDOM $RANDOM $RANDOM $RANDOM $RANDOM | md5 | cut -c -8)
FILENAME="abcdef-$R"
 2
Author: reto,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-05-31 15:48:52

Tome 16 bytes de /dev/random, conviértalos a hexadecimal, tome la primera línea, elimine la dirección, elimine los espacios.

head /dev/random -c16 | od -tx1 -w16 | head -n1 | cut -d' ' -f2- | tr -d ' '

Suponiendo que "sin recurrir a un programa" significa "usar solo programas que están fácilmente disponibles", por supuesto.

 1
Author: Thomas,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2010-05-08 11:28:55

Si está en Linux, Python vendrá preinstalado. Así que puedes ir por algo similar a lo siguiente:

python -c "import uuid; print str(uuid.uuid1())"

Si no le gustan los guiones, use la función reemplazar como se muestra a continuación

python -c "import uuid; print str(uuid.uuid1()).replace('-','')"
 1
Author: Thyag,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-08-11 22:13:20

La primera respuesta es buena, pero por qué fork cat si no es necesario.

tr -dc 'a-f0-9' < /dev/urandom | head -c32
 1
Author: Josiah DeWitt,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-04-13 23:27:54

Esperamos agregar una (tal vez) mejor solución a este tema.

Aviso: esto solo funciona con bash4 y algún implemento de mktemp (por ejemplo, el GNU)

Prueba esto

fn=$(mktemp -u -t 'XXXXXX')
echo ${fn/\/tmp\//}

Este es dos veces más rápido que head /dev/urandom | tr -cd 'a-f0-9' | head -c 32, y ocho veces más rápido que cat /dev/urandom | tr -cd 'a-f0-9' | head -c 32.

Punto de referencia:

Con mktemp:

#!/bin/bash
# a.sh
for (( i = 0; i < 1000; i++ ))
do
    fn=$(mktemp -u -t 'XXXXXX')
    echo ${fn/\/tmp\//} > /dev/null
done

time ./a.sh 
./a.sh  0.36s user 1.97s system 99% cpu 2.333 total

Y el otro:

#!/bin/bash
# b.sh
for (( i = 0; i < 1000; i++ ))
do
    cat /dev/urandom | tr -dc 'a-zA-Z0-9' | head -c 32 > /dev/null
done

time ./b.sh 
./b.sh  0.52s user 20.61s system 113% cpu 18.653 total
 0
Author: 罗泽轩,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-06-09 15:43:51

Otra cosa que puede agregar es ejecutar el comando date de la siguiente manera:

date +%S%N

Lee tiempo de no segundos y el resultado agrega mucha aleatoriedad.

 0
Author: user3174711,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-07-12 10:14:37