web-dev-qa-db-fra.com

Générer un nom de fichier aléatoire dans un shell

Je voudrais générer un nom de fichier aléatoire dans unix Shell (disons tcshell). Le nom de fichier doit être composé de 32 lettres hexadécimales aléatoires, par exemple:

c7fdfc8f409c548a10a0a89a791417c5

(auquel j'ajouterai ce qui est nécessaire). Le but est de pouvoir le faire uniquement dans Shell sans recourir à un programme.

66
R S

En supposant que vous soyez sur un Linux, les éléments suivants devraient fonctionner:

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

Ce n'est que pseudo-aléatoire si votre système est à faible entropie, mais que sa terminaison est garantie (sous Linux). Si vous avez besoin de données réellement aléatoires, cat /dev/random au lieu de /dev/urandom. Cette modification rendra votre code bloqué jusqu'à ce que suffisamment d'entropie soit disponible pour produire une sortie réellement aléatoire, ce qui pourrait ralentir votre code. Pour la plupart des utilisations, la sortie de /dev/urandom est suffisamment aléatoire.

Si vous utilisez OS X ou un autre BSD, vous devez le modifier comme suit:

cat /dev/urandom | env LC_CTYPE=C tr -cd 'a-f0-9' | head -c 32
110
fmark

pourquoi ne pas utiliser la commande unix mktemp:

$ TMPFILE=`mktemp tmp.XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX` &&  echo $TMPFILE
tmp.MnxEsPDsNUjrzDIiPhnWZKmlAXAO8983
40
Oleg Razgulyaev

Une commande, pas de pipe, pas de boucle:

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

Si vous n'avez pas besoin de la nouvelle ligne, par exemple lorsque vous l'utilisez dans une variable:

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

L'utilisation de "16" génère 32 chiffres hexadécimaux.

17

Testé en zsh, devrait fonctionner avec tous les Shell compatibles BASH!

#!/bin/zsh

SUM=`md5sum <<EOF
$RANDOM
EOF`

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

echo "Your new filename: $FN"

Exemple:

$ zsh ranhash.sh
Your new filename: 2485938240bf200c26bb356bbbb0fa32
$ zsh ranhash.sh
Your new filename: ad25cb21bea35eba879bf3fc12581cc9
5
LukeN

Comme vous l'avez probablement remarqué dans chacune des réponses, vous avez généralement devez "recours à un programme".

Cependant, sans utiliser aucun exécutable externe, dans Bash et 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

Modifiez la majuscule x dans la chaîne de format en une majuscule X pour que les caractères hexadécimaux alphabétiques soient en majuscules.

Voici une autre façon de le faire dans Bash mais sans boucle explicite:

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

Dans la suite, "premier" et "deuxième" printf fait référence à l'ordre dans lequel ils sont exécutés plutôt qu'à l'ordre dans lequel ils apparaissent dans la ligne.

Cette technique utilise le développement d'accolade pour produire une liste de 32 nombres aléatoires mod 16 suivis chacun d'un espace et de l'un des nombres compris entre accolades suivis d'un autre espace (par exemple 11 00). Pour chaque élément de cette liste, la première printf supprime tous les caractères sauf les deux premiers en utilisant sa chaîne de formatage (%.2), en laissant un seul chiffre suivi d'un espace chacun ou de deux chiffres. L'espace dans la chaîne de format garantit qu'il y a alors au moins un espace entre chaque numéro de sortie.

La substitution de commande contenant la première printf n'est pas citée, de sorte que la division de Word est effectuée et que chaque numéro passe à la seconde printf en tant qu'argument séparé. Là, les nombres sont convertis en hexa par la chaîne de formatage %X et ils sont ajoutés les uns aux autres sans espaces (puisqu'il n'y en a pas dans la chaîne de format) et le résultat est stocké dans la variable nommée string.

Lorsque printf reçoit plus d'arguments que ses comptes de chaîne de format, le format est appliqué à chaque argument jusqu'à ce qu'ils soient tous consommés. S'il y a moins d'arguments, la chaîne de format sans correspondance (partie) est ignorée, mais cela ne s'applique pas dans ce cas.

Je l'ai testé avec Bash 3.2, 4.4 et 5.0-alpha. Mais cela ne fonctionne pas dans zsh (5.2) ou ksh (93u +) car RANDOM n'est évalué qu'une seule fois dans le développement de l'accolade dans ces shells.

Notez qu'en raison de l'utilisation de l'opérateur mod sur une valeur comprise entre 0 et 32767, la distribution des chiffres à l'aide des extraits pourrait être faussée (sans parler du fait que les nombres sont pseudo aléatoires en premier lieu) . Cependant, étant donné que nous utilisons les mod 16 et 32 ​​768 divisibles par 16, ce ne sera pas un problème ici.

Dans tous les cas, la bonne façon de faire consiste à utiliser mktemp comme dans de Oleg Razgulyaev answer.

5

Encore une autre façon [tm].

R=$(echo $RANDOM $RANDOM $RANDOM $RANDOM $RANDOM | md5 | cut -c -8)
FILENAME="abcdef-$R"
3
reto

Cette réponse est très similaire à fmarks, je ne peux donc pas en prendre le crédit, mais j'ai trouvé les combinaisons de commandes cat et tr assez lentes et cette version un peu plus rapide. Vous avez besoin d'hexdump.

hexdump -e '/1 "%02x"' -n32 < /dev/urandom
3
srclosson

La première réponse est bonne mais pourquoi fourchette chat si pas nécessaire 

tr -dc 'a-f0-9' < /dev/urandom | head -c32
2
Josiah DeWitt

Si vous êtes sous Linux, Python sera pré-installé. Donc, vous pouvez aller pour quelque chose semblable au ci-dessous:

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

Si vous n'aimez pas les tirets, utilisez la fonction de remplacement comme indiqué ci-dessous

python -c "import uuid; print str(uuid.uuid1()).replace('-','')"
1
Thyag

Saisissez 16 octets à partir de /dev/random, convertissez-les en hexa, prenez la première ligne, supprimez l'adresse, supprimez les espaces.

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

En supposant que "sans recourir à un programme" signifie "n'utilisant que des programmes facilement disponibles", bien sûr.

1
Thomas

J'espère ajouter une (peut-être) meilleure solution à ce sujet.

Remarque: cela ne fonctionne qu'avec bash4 et quelques implémentations de mktemp (par exemple, celle GNU)

Essaye ça

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

Celui-ci est deux fois plus rapide que head /dev/urandom | tr -cd 'a-f0-9' | head -c 32 et huit fois plus rapide que cat /dev/urandom | tr -cd 'a-f0-9' | head -c 32.

Référence:

Avec 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

Et l'autre:

#!/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
1
罗泽轩

uuidgen génère exactement ceci, sauf que vous devez supprimer des traits d'union. J'ai donc trouvé que c'était le moyen le plus élégant (du moins pour moi) d'y parvenir. Cela devrait fonctionner sur Linux et OS X immédiatement.

uuidgen | tr -d '-'
0
danran

Une autre chose que vous pouvez ajouter exécute la commande date comme suit:

date +%S%N

Lit le temps non secondes et le résultat ajoute beaucoup de hasard.

0
user3174711

Si vous avez openssl dans votre système, vous pouvez l’utiliser pour générer des chaînes hexagonales aléatoires (il peut également s'agir de -base64) avec une longueur définie. Je l'ai trouvé assez simple et utilisable dans les travaux cron in one line.

 openssl Rand -hex 32
 8c5a7515837d7f0b19e7e6fa4c448400e70ffec88ecd811a3dce3272947cb452
0
Alex