Come creare un UUID in bash?


185

In Java è possibile creare un UUID casuale :

UUID uuid = UUID.randomUUID();

Come fare questo in Bash?

Risposte:


225

Vedi il uuidgenprogramma che fa parte del pacchetto e2fsprogs .

Secondo questo , libuuidora fa parte di util-linux e l'inclusione in e2fsprogs è in fase di eliminazione. Tuttavia, sui nuovi sistemi Ubuntu, uuidgenè ora nel uuid-runtimepacchetto.

Per creare un uuid e salvarlo in una variabile:

uuid=$(uuidgen)

Sul mio sistema Ubuntu, i caratteri alfa vengono visualizzati in minuscolo e sul mio sistema OS X, vengono visualizzati in maiuscolo (grazie a David per averlo sottolineato in un commento).

Per passare a tutte le maiuscole (dopo averlo generato come sopra):

uuid=${uuid^^}

Per passare a tutte le lettere minuscole:

uuid=${uuid,,}

Se, ad esempio, hai due UUID e vuoi confrontarli in Bash, ignorando il loro caso, puoi fare un tolower()confronto di stili come questo:

if [[ ${uuid1,,} == ${uuid2,,} ]]

7
ehi, non è giusto! i miei e2fsprogs non sono venuti con quello! ne voglio uno, dove lo trovo? (aggiornamento: ahhh ... Debian lo inserisce nel uuid-runtimepacchetto senza una ragione apparente ... +1 per te)
Quack Quixote

uuidgen viene incorporato su freeBSD. non è sempre nel pacchetto e2fsprogs.
Brava persona,

1
@Rob: per rispondere alla domanda originale, è per le etichette dell'unità .
Dennis Williamson,

2
Noto uuidgen su Mac emette in maiuscolo mentre su Ubuntu (uuidgen da util-linux 2.20.1) in minuscolo. Perché la differenza Anche Ubuntu ha elencato da dove proviene lo strumento ma su Mac, non ci sono informazioni sulla versione né da quale pacchetto proviene.
David,

1
@ David: credo che faccia parte del sistema operativo di base su OS X. Non ho idea del perché uno sia maiuscolo e l'altro sia inferiore. Non importa davvero poiché entrambi rappresentano caratteri esadecimali validi ( echo -e 'f\nF' | grep '[[:xdigit:]]'genera entrambe le righe). Se è importante per te e hai Bash 4, puoi farlo per renderlo minuscolo: uuid=$(uuidgen); uuid=${uuid,,}o questo per renderlo maiuscolo: uuid=$(uuidgen); uuid=${uuid^^}o qualcosa del genere per fare un tolower()test di stile:if [[ ${uuid1,,} == ${uuid2,,} ]]
Dennis Williamson,

168

Per aggiungere varietà senza aggiungere dipendenze esterne, su Linux puoi fare:

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

Per propagare cattive pratiche, su FreeBSD , sotto il livello di compatibilità di linux (linuxulator?),

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

Riferimenti:


19
Questo e spettacolare.
Tom O'Connor,

3
Questo dovrebbe essere evitato poiché è altamente non portatile (anche se FreeBSD fornisce / compat / linux / proc / sys / kernel / random / uuid per applicazioni scritte male)
Good Person

1
Si adatta perfettamente per l'utilizzo all'interno dell'immagine initrd
Maximilian

2
Questa dovrebbe essere la risposta migliore!
dguerri,

6
Questa è una risposta migliore per configurazioni davvero minime, come un contenitore Docker.
Jacderida,

34

Solo per completezza ... C'è anche un generatore UUID installato con il dbuspacchetto su Debian. Mi mancava guardarmi intorno prima. Probabilmente è lo stesso algoritmo del pacchetto e2fsprogs, ma non aggiunge i trattini, quindi potrebbe essere un po 'più pulito per te:

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

$ dbus-uuidgen
d17b671f98fced5649a856a54b51c9e6

Grawity aggiunge un suggerimento di sicurezza: "Gli UUID DBus non sono correlati o compatibili con RFC 4122. Inoltre, dbus-uuidgen utilizza sempre il timestamp Unix come gli ultimi 4 byte. Pertanto potrebbero non essere adatti per alcuni usi." (Grazie, Grawity, avrei dovuto individuarlo nella manpage.)


7
Gli UUID DBus non sono correlati o compatibili con RFC 4122. Inoltre, dbus-uuidgenutilizza sempre il timestamp Unix come gli ultimi 4 byte. Quindi potrebbero non essere adatti per alcuni usi.
Grawity

lo stesso
vale

20

Se non vuoi dipendere da altri eseguibili o non puoi usarli, ecco la versione bash pura da qui :

# 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

La Tvariabile può essere eliminata e il for Tloop può essere modificato in: case $N in 3 | 5 | 7 | 9) printf '-';; esac(suddiviso su righe separate se preferito).
Dennis Williamson,

1
Ho aggiunto un commento al codice sul link github che mostra una versione usando caseper eliminare sia le ifistruzioni che l' foristruzione interna . Rende il codice molto più ordinato. Nota che entrambi B%15dovrebbero essere B%16e B%255dovrebbero essere B%256.
Dennis Williamson,

mettilo online a un url in modo che le persone possano source <(curl url)
cercarlo

19

Ho trovato questo script "one-liner" utile dove uuidgen non è disponibile. Questo evita anche qualsiasi necessità di installare moduli esterni per Perl o Python.

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

Testato su SnowLeopard, Red Hat Valhalla, Solaris 9 4/04 e versioni successive con successo. Sono curioso di sapere se questo è incline alla non unicità, ma non sono stato 'morso' negli ultimi 10 anni. Certo, head -1potrebbe essere sostituito head -_other-value_ | tail -1anche con .

Spiegare,

/dev/randome /dev/urandomsono generatori casuali del kernel.

od (dump ottale) ha un interruttore di uscita esadecimale (-x) che produce 16 byte per linea.

head-n [| tail -1] (dove n> 0) estrae solo una riga dell'output precedente.

awkimposta OutputFieldSeparator come un trattino ovunque si presenti una virgola nell'istruzione print. Specificando i campi 2-9 in modo indipendente, controlliamo i trattini e rimuoviamo il contatore indice / offset che 'od' prefigura ogni linea di output con.

Il risultato è un modello di 8-4-4-4-12caratteri minuscoli a-f0-9.

993bb8d7-323d-b5ee-db78-f976a59d8284

1
Brillante! solo una riga senza dipendenze, compatibile con BSD / macOS ... fantastico
dinigo

Da NON usare "coda -1". Se esegui solo "od -x / dev / urandom" da solo, va avanti indefinitamente, producendo continuamente più righe di dati casuali. "tail -1" può semplicemente rimanere lì per sempre in attesa dell'ultima riga. Altrimenti, è una buona soluzione.
UncaAlby,

Nota che la coda è solo nella "spiegazione" come parametro facoltativo quando il numero di linee emesse dalla testa è maggiore di uno. Lì per garantire la ricezione di una sola riga di 16 byte da awk e non fa parte del comando originale. Il tubo a testa da od igienizza già l'uscita per la tubazione alla coda -1. Nella mia esperienza, l'unica volta che la coda aspetta per sempre è con un argomento -f. Mi scuso se la spiegazione non era chiara in cui si afferma che l'uso della coda -1 è necessario solo quando l'uscita della testa produce più di una riga.
dan

2
Evitare Non utilizzare questo, viola completamente le specifiche UUID. Solo l'UUID versione 4 può essere casuale in questo modo.
jlh

3
@jlh Non sono sicuro del perché questa domanda sia stata bloccata, ma ecco una versione fissa che rende questo approccio conforme a 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

Proprio così Python non si sente escluso:

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

Per usarlo nella shell:

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

Vedi l' UUID della documentazione di Python per i tipi di UUID che possono essere generati.

Per generare un file compatibile con ID macchina systemd su una macchina non systemd, è possibile utilizzare Python per farlo in questo modo:

python -c 'import re; import uuid; print re.sub("-","",str(uuid.uuid4()))' \
 > /etc/machine-id

sei un built-in?
Alexander Mills

Python ha mai funzionato? Ottengo questo `File" <stringa> ", riga 1 import uuid; print uuid.uuid1 () ^ SintassiError: sintassi non valida `
Alexander Mills

1
Utilizzare python3 -c "import uuid; print(uuid.uuid4())"per python3
abdusco il

11

Perl fornisce una libreria UUID basata sul e2fsprogspacchetto. Sul mio sistema Debian è il libuuid-perlpacchetto. Ecco un esempio di una riga; vedere man uuiddi più:

$ 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

Questo sarebbe banale da aggiungere a uno shellscript con backtick o $()notazione:

#!/bin/bash
# ...do some stuff
$myvar = $(perl -e 'use UUID;  UUID::generate($uuid);  UUID::unparse($uuid, $string);  print "$string";')
# ...do some more stuff

+1 - Aiutami molto!
rafa.ferreira,


1

Ho scritto una piccola funzione di Bash usando Python per generare un numero arbitrario di UUID in blocco:

# 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"')]))'
}

Se preferisci lettere minuscole, modifica:

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

Per:

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

1

Consulta la libreria UUID OSSP ( http://www.ossp.org/pkg/lib/uuid/ ) e valuta la possibilità di installarla. Alcuni progetti lo offrono come opzione (ad esempio PostgreSQL). Gestisce correttamente gli UUID versione 3 e versione 5 , che andavano oltre ciò che la mia libreria installata (ad es. E2fsprogs) poteva gestire. Fortunatamente, openSUSE ce l'ha in uno dei principali repository. Far funzionare una versione con Windows (ad es. Cygwin) o MySQL è stato un difetto. Sembra che sia tempo di passare a Linux / PostgreSQL / Python (e ho adorato la GUI di SQLyog su MySQL / MariaDB) poiché ho davvero bisogno degli UUID v3 e v5.


Accetto completamente! Nel mio caso d'uso è stato perfetto in quanto supporta anche lo spazio dei nomi tramite il -v3 ns:URL custom-datameccanismo di seeding.
Roberto Andrade,

1

Sono sicuro che alcuni arriveranno qui e stanno solo cercando un modo semplice per generare un ID univoco da utilizzare nei loro script e non deve essere un vero UUID.

In tal caso, puoi semplicemente fare quanto segue, che genererà un ID univoco fino al secondo, quindi se esegui questo più volte in un secondo, otterrai comunque lo stesso risultato.

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

genererà ID come il seguente in base all'ora di sistema corrente:

U1454423662

NOTA: se sei su Linux o se Coreutils è installato su un Mac, puoi utilizzare quanto segue per generare un ID univoco per il nanosecondo:

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

o se preferisci una soluzione basata su Python fino al nanosecondo, che dovrebbe funzionare quasi ovunque, esegui:

MYUID=U$(python -c'import time; print repr(time.time())')
echo $MYUID

1
Questa è nel complesso una pessima pratica. I computer moderni sono perfettamente in grado di eseguire molte cose in parallelo e di completare rapidamente attività seriali, ma questo ID sarà identico per tutte le invocazioni che si trovano entro un secondo dall'altro. Per non parlare di altri computer che eseguono questo script contemporaneamente. Un'opzione migliore ma ancora non eccezionale sarebbe mktemp -ucome in MYID="$(mktemp -u)". Se puoi permetterti di avere file temporanei vuoti in sospeso fino al riavvio, rilascia -u:MYID="$(mktemp)"
Chris Harrington,

Ehi ... buoni punti sull'unico aspetto del secondo punto ... Aggiungerò alcune note sopra ...
Brad Parks

1

Questo thread, con i suoi vari esempi, mi è stato davvero utile. Spesso ho bisogno di funzioni uuid da diversi ambienti. E mentre adoro gli esempi di puro bash, a volte è più comodo usare una libreria di una lingua diversa.

Quindi solo per completezza, ruby ​​(1.9.3+) ha il modulo SecureRandom incorporato che contiene una serie di utili funzioni hash e id. Dal bash cli, puoi farlo.

ruby -r securerandom -e 'puts SecureRandom.uuid'

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`

3
Una spiegazione in più aiuterebbe la tua risposta
Dave M

x = od -X -A n /dev/random | head -1 | cut -c3-38 ti dà questo sotto 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, tornato a fare la vergogna dopo molti anni di distanza, questo è molto al limite della mia attuale conoscenza. Spero che abbatterlo un po 'aiuti. salute, andyfff
andyfff,

-1

Se si utilizza Java 10.

$ jshell
jshell> import java.util.*
jshell> String id = UUID.randomUUID().toString();

Java 10 non è bash.
Kasperd,

Ho appena fatto un esempio di quanto velocemente può generare un UUID sul terminale senza eseguire un programma Java. Le persone hanno fornito esempi sull'uso di dbus-uuidgen e uuidgen . Cosa c'è di sbagliato nell'usare jshell?
Amit

1
@amit il punto è che devi dare un esempio di dove jshellpuò essere usato negli script bash e non come comando interattivo . Questo è molto chiaro nel post originale.
Samveen,

Se devi fare qualcosa per elencarlo, potresti farlo echo "System.out.println(java.util.UUID.randomUUID().toString())" | /Library/Java/JavaVirtualMachines/openjdk-11.0.1.jdk/Contents/Home/bin/jshell -s | grep -v ">" Ma è molto più lungo di quanto non lo sia uuidgen.
mlk
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.