Comment créer un UUID dans bash?

185

En Java, il est possible de créer un UUID aléatoire :

UUID uuid = UUID.randomUUID();

Comment faire cela en Bash?

Raoulsson
la source

Réponses:

225

Voir le uuidgenprogramme qui fait partie du paquet e2fsprogs .

Selon cela , celalibuuid fait maintenant partie d' util-linux et l'inclusion dans e2fsprogs est en train de disparaître. Cependant, sur les nouveaux systèmes Ubuntu, uuidgenest maintenant dans le uuid-runtimepaquet.

Pour créer un uuid et le sauvegarder dans une variable:

uuid=$(uuidgen)

Sur mon système Ubuntu, les caractères alpha sont écrits en minuscule et sur mon système OS X, ils sont en majuscule (merci à David de l'avoir signalé dans un commentaire).

Pour passer à toutes les majuscules (après l'avoir généré comme ci-dessus):

uuid=${uuid^^}

Pour basculer vers tous les minuscules:

uuid=${uuid,,}

Si, par exemple, vous avez deux UUID et que vous voulez les comparer dans Bash, en ignorant leur cas, vous pouvez effectuer une tolower()comparaison de style comme ceci:

if [[ ${uuid1,,} == ${uuid2,,} ]]
Dennis Williamson
la source
7
hé, pas juste! mes e2fsprogs ne sont pas venus avec ça! J'en veux un, où puis-je l'obtenir? (mise à jour: ahhh ... Debian le colle dans le uuid-runtimepaquet sans raison apparente ... +1 à vous)
Quack Quichotte
uuidgen est intégré à freeBSD. ce n'est pas toujours dans le paquet e2fsprogs.
Bonne personne
1
@Rob: Pour répondre à votre question initiale, c'est pour les étiquettes de lecteurs .
Dennis Williamson
2
Je remarque que uuidgen sur Mac émet en majuscule tandis que sur Ubuntu (uuidgen à partir de util-linux 2.20.1) en minuscule. Pourquoi la différence? Ubuntu a également répertorié l’origine de l’outil, mais sur Mac, il n’ya pas d’informations sur la version ni sur le paquet dont il provient.
David
1
@ David: Je pense que cela fait partie du système d'exploitation de base sous OS X. Je ne sais pas pourquoi l'une est en majuscule et l'autre est plus basse. Cela n'a pas vraiment d'importance puisque l'un ou l'autre représente des caractères hexadécimaux valides ( echo -e 'f\nF' | grep '[[:xdigit:]]'génère les deux lignes). Si cela vous importe et que vous avez Bash 4, vous pouvez le faire pour le mettre en minuscule: uuid=$(uuidgen); uuid=${uuid,,}ou le faire pour le mettre en majuscule: uuid=$(uuidgen); uuid=${uuid^^}ou quelque chose du tolower()genre pour faire un test de style:if [[ ${uuid1,,} == ${uuid2,,} ]]
Dennis Williamson
168

Pour ajouter de la variété sans ajouter de dépendances externes, vous pouvez faire sous Linux :

UUID=$(cat /proc/sys/kernel/random/uuid)

Pour propager les mauvaises pratiques, sur FreeBSD , sous la couche de compatibilité Linux (linuxulator?),

UUID=$(cat /compat/linux/proc/sys/kernel/random/uuid)

Références:

Samveen
la source
19
C'est génial.
Tom O'Connor
3
Ceci devrait être évité car il est hautement non portable (bien que FreeBSD fournisse / compat / linux / proc / sys / kernel / random / uuid pour des applications mal écrites)
Bonne personne
1
Il convient parfaitement pour une utilisation dans une image initiale
Maximilian
2
Cela devrait être la meilleure réponse!
dguerri
6
C'est une meilleure réponse pour des configurations vraiment minimales, comme un conteneur Docker.
Jacderida
34

Juste pour être complet ... Il y a aussi un générateur d'UUID installé avec le dbuspaquet sur Debian. Je l'ai raté en regardant autour de moi plus tôt. C'est probablement le même algorithme que le paquet e2fsprogs, mais il n'ajoute pas les tirets, il pourrait donc être un peu plus propre pour vous:

$ uuidgen
387ee6b9-520d-4c51-a9e4-6eb2ef15887d

$ dbus-uuidgen
d17b671f98fced5649a856a54b51c9e6

Grawity ajoute un conseil de sécurité: "Les UUID de DBus ne sont pas liés ou compatibles avec le RFC 4122. En outre, dbus-uuidgen utilise toujours le timestamp Unix comme les 4 derniers octets. Ils pourraient donc ne pas convenir à certaines utilisations." (Merci, Grawity, j'aurais dû remarquer cela dans la page de manuel.)

Quack Quack
la source
7
Les UUID de DBus ne sont pas liés ou compatibles avec RFC 4122. De plus, dbus-uuidgenutilise toujours l'horodatage Unix comme les 4 derniers octets. Ils pourraient donc ne pas convenir à certaines utilisations.
Grawity
Les mêmes travaux sur Fedora-25, aussi ...
kmonsoor
20

Si vous ne voulez pas dépendre d'autres exécutables, ou si vous ne pouvez pas les utiliser, voici la version pure bash d' ici :

# Generate a pseudo UUID
uuid()
{
    local N B T

    for (( N=0; N < 16; ++N ))
    do
        B=$(( $RANDOM%255 ))

        if (( N == 6 ))
        then
            printf '4%x' $(( B%15 ))
        elif (( N == 8 ))
        then
            local C='89ab'
            printf '%c%x' ${C:$(( $RANDOM%${#C} )):1} $(( B%15 ))
        else
            printf '%02x' $B
        fi

        for T in 3 5 7 9
        do
            if (( T == N ))
            then
                printf '-'
                break
            fi
        done
    done

    echo
}

[ "$0" == "$BASH_SOURCE" ] && uuid
en aucune façon
la source
La Tvariable peut être éliminée et la for Tboucle peut être changée en: case $N in 3 | 5 | 7 | 9) printf '-';; esac(éclatée sur des lignes séparées si vous préférez).
Dennis Williamson
1
J'ai ajouté un commentaire au code sur le lien github montrant une version utilisant casepour éliminer les ifinstructions ainsi que l' forinstruction interne . Cela rend le code beaucoup plus ordonné. Notez que les deux B%15devraient être B%16et B%255devraient être B%256.
Dennis Williamson
mettez-le en ligne à une url afin que les gens puissent le source <(curl url)
trouver
19

J'ai trouvé ce script "one-liner" utile là où uuidgen n'est pas disponible. Cela évite également l’installation de modules externes pour Perl ou Python.

od -x /dev/urandom | head -1 | awk '{OFS="-"; print $2$3,$4,$5,$6,$7$8$9}'

Testé avec succès sur SnowLeopard, Red Hat Valhalla, Solaris 9 4/04 et plus récent. Je suis curieux de savoir si cela est sujet à la non-unicité, mais je n’ai pas été «mordu» au cours des 10 dernières années. Bien sûr, head -1pourrait être remplacé par head -_other-value_ | tail -1aussi.

Expliquer,

/dev/randomet /dev/urandomsont des générateurs aléatoires du noyau.

od (octal dump) a un commutateur de sortie hexadécimale (-x) produisant 16 octets par ligne.

head-n [| tail -1] (où n> 0) extrait une seule ligne de la sortie précédente.

awkdéfinit OutputFieldSeparator comme un trait d'union chaque fois qu'une virgule apparaît dans l'instruction d'impression. En spécifiant indépendamment les champs 2 à 9, nous contrôlons les traits d'union et supprimons le compteur d'index / décalage avec lequel 'od' préfixe chaque ligne de sortie.

Le résultat est un modèle de 8-4-4-4-12caractères minuscules a-f0-9.

993bb8d7-323d-b5ee-db78-f976a59d8284
dan
la source
1
Brillant! juste une seule ligne sans dépendance, compatible BSD / macOS ... great
dinigo
N'utilisez PAS "tail -1". Si vous exécutez simplement "od -x / dev / urandom", cela continue indéfiniment, en produisant continuellement plus de lignes de données aléatoires. "tail -1" peut rester assis là pour toujours en attendant la "dernière" ligne. Sinon, c'est une bonne solution.
UncaAlby
Veuillez noter que tail est uniquement dans "l'explication" en tant que paramètre facultatif lorsque le nombre de lignes sorties par head est supérieur à un. Là pour s'assurer de recevoir une seule ligne de 16 octets par awk, et ne fait pas partie de la commande d'origine. Le tuyau à partir de od assainit déjà la sortie pour tuyauterie à queue -1. D'après mon expérience, le seul temps d'attente pour toujours est avec un argument -f. Je m'excuse si l'explication n'était pas claire là où il est indiqué que l'utilisation de la queue -1 n'est nécessaire que lorsque la sortie de la tête produit plus d'une ligne.
dan
2
Ne l' utilisez pas , cela violerait complètement la spécification UUID. Seule la version 4 des UUID peut être aléatoire de la sorte.
jlh
3
@jlh Je ne sais pas pourquoi cette question a été verrouillée, mais voici une version corrigée qui rend cette approche conforme à la norme UUID-v4:od -x /dev/urandom | head -1 | awk '{OFS="-"; srand($6); sub(/./,"4",$5); sub(/./,substr("89ab",rand()*4,1),$6); print $2$3,$4,$5,$6,$7$8$9}'
Stuart P. Bentley
14

Juste pour que le python ne se sente pas exclu:

python  -c 'import uuid; print uuid.uuid1()'
2d96768e-02b3-11df-bec2-001e68b9d147

Pour l'utiliser dans le shell:

myvar=$(python  -c 'import uuid; print uuid.uuid1()')

Consultez l' UUID de la documentation Python pour connaître les types d'UUIDS pouvant être générés.

Pour générer un fichier compatible d'identifiant de machine systemd sur une machine autre que systemd, vous pouvez utiliser python pour le faire de cette façon:

python -c 'import re; import uuid; print re.sub("-","",str(uuid.uuid4()))' \
 > /etc/machine-id
davey
la source
uuid est-il intégré?
Alexander Mills
Le python a-t-il déjà fonctionné? Je reçois ce `Fichier" <chaîne> ", ligne 1 import uuid; print uuid.uuid1 () ^ SyntaxError: syntaxe non valide `
Alexander Mills
1
Utilisez python3 -c "import uuid; print(uuid.uuid4())"pour python3
abdusco
11

Perl fournit une bibliothèque UUID basée sur le e2fsprogspackage. Sur mon système Debian, c'est le libuuid-perlpaquet. Voici un exemple one-liner; voir man uuidpour plus:

$ perl -e 'use UUID;  UUID::generate($uuid);  UUID::unparse($uuid, $string);  print "my new UUID is $string \n";'
my new UUID is 3079e9ce-41d4-4cf3-9f90-d12f8bb752e4

Ce serait trivial d'ajouter à un shellscript avec des guillemets ou une $()notation:

#!/bin/bash
# ...do some stuff
$myvar = $(perl -e 'use UUID;  UUID::generate($uuid);  UUID::unparse($uuid, $string);  print "$string";')
# ...do some more stuff
Quack Quack
la source
+1 - Aidez-moi beaucoup!
Rafa.ferreira
1

J'ai écrit une petite fonction Bash en utilisant Python pour générer un nombre arbitraire d'UUID en bloc:

# uuid [count]
#
# Generate type 4 (random) UUID, or [count] type 4 UUIDs.
function uuid()
{
    local count=1
    if [[ ! -z "$1" ]]; then
        if [[ "$1" =~ [^0-9] ]]; then
            echo "Usage: $FUNCNAME [count]" >&2
            return 1
        fi

        count="$1"
    fi

    python -c 'import uuid; print("\n".join([str(uuid.uuid4()).upper() for x in range('"$count"')]))'
}

Si vous préférez les minuscules, changez:

python -c 'import uuid; print("\n".join([str(uuid.uuid4()).upper() for x in range('"$count"')]))'

À:

python -c 'import uuid; print("\n".join([str(uuid.uuid4()) for x in range('"$count"')]))'
Volonté
la source
1

Consultez la bibliothèque UUID OSSP ( http://www.ossp.org/pkg/lib/uuid/ ) et envisagez de l’installer. Certains projets l’offrent en option (par exemple PostgreSQL). Il gère correctement les UUID des versions 3 et 5 , ce qui allait au-delà de ce que ma bibliothèque installée (par exemple, e2fsprogs) pouvait gérer. Heureusement, openSUSE l’a dans l’un des principaux dépôts. Faire fonctionner une version avec Windows (par exemple, Cygwin) ou MySQL a été un fléau. On dirait qu'il est temps de passer à Linux / PostgreSQL / Python (et j'ai tellement adoré l'interface graphique SQLyog pour MySQL / MariaDB) car j'ai vraiment besoin des UUID v3 et v5.

utilisateur2351170
la source
Complètement d'accord! Pour mon cas d'utilisation, il était parfait car il prend également en charge l'espacement de noms via le -v3 ns:URL custom-datamécanisme d'ensemencement.
Roberto Andrade
1

Je suis certain que certains vont arriver ici et cherchent simplement un moyen simple de générer un identifiant unique à utiliser dans leurs scripts. Il n'est pas nécessaire que ce soit un véritable UUID.

Si tel est le cas, vous pouvez simplement procéder comme suit, ce qui générera un identifiant unique à la seconde près. Par conséquent, si vous l'exécutez plusieurs fois par seconde, vous obtiendrez toujours le même résultat.

MYID="U$(date +%s)"
echo $MYID

générera des identifiants comme ceux suivants basés sur l’heure système actuelle:

U1454423662

REMARQUE: Si vous êtes sous Linux ou que Coreutils est installé sur un mac, vous pouvez utiliser ce qui suit pour générer un identifiant unique à la nanoseconde:

MYID="U$(date +%s%N)"
echo $MYID

ou si vous préférez une solution à base de python jusqu'à la nanoseconde, qui devrait fonctionner presque partout, lancez:

MYUID=U$(python -c'import time; print repr(time.time())')
echo $MYUID
Brad Parks
la source
1
C’est dans l’ensemble une très mauvaise pratique. Les ordinateurs modernes sont parfaitement capables d’exécuter beaucoup de choses en parallèle et d’accomplir rapidement des tâches série, mais cet ID sera identique pour tous les appels qui se situent à une seconde près. Sans parler des autres ordinateurs exécutant ce script en même temps. Une option meilleure, mais pas encore excellente, serait mktemp -ucomme dans MYID="$(mktemp -u)". Si vous pouvez vous permettre d'avoir des fichiers temporaires vides en attente jusqu'au redémarrage, laissez tomber le -u:MYID="$(mktemp)"
Chris Harrington
Hey ... bons points sur l'unique unique au deuxième point ... Je vais ajouter quelques notes ci-dessus ...
Brad Parks
1

Ce fil, avec ses exemples variés, m’était vraiment utile. J'ai souvent besoin de fonctions uuid de différents environnements. Et bien que j'adore les exemples purs bash, il est parfois plus pratique d'utiliser une bibliothèque d'un autre langage.

Ainsi, ruby ​​(1.9.3+) intègre le module SecureRandom contenant un certain nombre de fonctions de hachage et d’id utiles. De la bash cli, vous pouvez le faire.

ruby -r securerandom -e 'puts SecureRandom.uuid'
wbr
la source
0
ran=`od -X -A n /dev/random | head -1 | cut -c3-38`

correlation_id=`echo ${ran} | cut -c1-8`-`echo ${ran} | cut -c10-13`-`echo ${ran} | cut -c14-17`-`echo ${ran} | cut -c19-22`-`echo ${ran} | cut -c23-26``echo ${ran} | cut -c28-35`
Andyfff
la source
3
Un peu plus d'explication aiderait votre réponse
Dave M
x = od -X -A n /dev/random | head -1 | cut -c3-38 vous donne ceci ci-dessous echo $ x 4151540a 1f7d0bef 8a0725fb d26183a3 uuid = echo ${x} | cut -c1-8- echo ${x} | cut -c10-13- echo ${x} | cut -c14-17- echo ${x} | cut -c19-22- echo ${x} | cut -c23-26``echo ${x} | cut -c28-35 echo $ uuid 4151540a-1f7d-0bef-8a07-25fbd26183a3
andyfff
Dave M, de retour en train de jouer après plusieurs années d'absence, c'est vraiment à la limite de mes connaissances actuelles. J'espère que le décomposer un peu aide. salutations, andyfff
andyfff
-1

Si vous utilisez Java 10.

$ jshell
jshell> import java.util.*
jshell> String id = UUID.randomUUID().toString();
amit
la source
Java 10 n'est pas bash.
Kasperd
Je viens de donner un exemple de la rapidité avec laquelle il peut générer un UUID sur un terminal sans exécuter de programme java. Les gens ont donné des exemples d'utilisation de dbus-uuidgen et d' uuidgen . Quoi de mal à utiliser jshell?
amit
1
@amit le fait est que vous devez donner un exemple où vous jshellpouvez utiliser un script bash , et non comme une commande interactive . C'est très clair dans le post original.
Samveen
Si vous devez faire quelque chose, faites-le, echo "System.out.println(java.util.UUID.randomUUID().toString())" | /Library/Java/JavaVirtualMachines/openjdk-11.0.1.jdk/Contents/Home/bin/jshell -s | grep -v ">" mais c'est beaucoup plus long que ça uuidgen.
mlk