Wie erstelle ich eine UUID in bash?

185

In Java ist es möglich, eine zufällige UUID zu erstellen :

UUID uuid = UUID.randomUUID();

Wie geht das in Bash?

Raoulsson
quelle

Antworten:

225

Sehen Sie sich das uuidgenProgramm an, das Teil des e2fsprogs- Pakets ist.

Nach diesem , libuuidist jetzt Teil von util-linux und die Aufnahme in e2fsprogs wird eingestellt. Allerdings ist auf neuen Ubuntu-Systemen uuidgenjetzt im uuid-runtimePaket.

So erstellen Sie eine UUID und speichern sie in einer Variablen:

uuid=$(uuidgen)

Auf meinem Ubuntu-System werden die Buchstaben als Kleinbuchstaben und auf meinem OS X-System als Großbuchstaben ausgegeben (danke an David, der dies in einem Kommentar hervorgehoben hat).

So wechseln Sie in Großbuchstaben (nach dem Generieren wie oben):

uuid=${uuid^^}

So wechseln Sie zu Kleinbuchstaben:

uuid=${uuid,,}

Wenn Sie zum Beispiel zwei UUIDs haben und diese in Bash vergleichen möchten, ohne die Groß- und Kleinschreibung zu beachten, können Sie einen tolower()Stilvergleich wie folgt durchführen:

if [[ ${uuid1,,} == ${uuid2,,} ]]
Dennis Williamson
quelle
7
hey nein fair meine e2fsprogs sind damit nicht gekommen! Ich will eins, wo bekomme ich es her? (Update: ahhh ... Debian steckt es uuid-runtimeohne ersichtlichen Grund in das Paket ... +1 für Sie)
Quacksalber Quixote
uuidgen ist in freeBSD integriert. es ist nicht immer im e2fsprogs-Paket enthalten.
Gute Person
1
@Rob: Zur Beantwortung Ihrer ursprünglichen Frage werden Laufwerksbezeichnungen verwendet .
Dennis Williamson
2
Ich stelle fest, dass uuidgen auf dem Mac in Großbuchstaben und auf Ubuntu (uuidgen von util-linux 2.20.1) in Kleinbuchstaben ausgegeben wird. Warum der Unterschied? Ubuntu listete auch auf, wo das Tool herkam, aber auf Mac gibt es weder Versionsinformationen noch das Paket, von dem es stammte.
David
1
@ David: Ich glaube, es ist Teil des Basisbetriebssystems unter OS X. Ich habe keine Ahnung, warum einer in Großbuchstaben und der andere in Kleinbuchstaben geschrieben ist. Es spielt keine Rolle, da beide gültige Hexadezimalzeichen darstellen ( echo -e 'f\nF' | grep '[[:xdigit:]]'beide Zeilen ausgeben). Wenn es eine Rolle für Sie tut , und Sie haben Bash 4, können Sie dies tun , um es tiefer Fall zu machen: uuid=$(uuidgen); uuid=${uuid,,}oder diese Großbuchstaben zu machen: uuid=$(uuidgen); uuid=${uuid^^}oder etwas in dieser Richtung eine tun tolower()Stil - Test:if [[ ${uuid1,,} == ${uuid2,,} ]]
Dennis Williamson
168

Unter Linux können Sie Folgendes tun, um die Vielfalt zu erhöhen, ohne externe Abhängigkeiten hinzuzufügen :

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

Um schlechte Praktiken unter FreeBSD unter der Linux-Kompatibilitätsebene (linuxulator?) Zu verbreiten,

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

Verweise:

Samveen
quelle
19
Das ist fantastisch.
Tom O'Connor
3
Dies sollte vermieden werden, da es in hohem Maße nicht portierbar ist (obwohl FreeBSD / compat / linux / proc / sys / kernel / random / uuid für schlecht geschriebene Anwendungen bereitstellt)
Gute Person
1
Es passt perfekt für die Verwendung in initrd Bild
Maximilian
2
Dies sollte die beste Antwort sein!
Dguerri
6
Dies ist eine bessere Antwort für wirklich minimale Setups wie einen Docker-Container.
Jacderida
34

Der Vollständigkeit halber ... Es gibt auch einen UUID-Generator, der mit dem dbusPaket auf Debian installiert ist . Ich habe es vermisst, als ich mich früher umgesehen habe. Es ist wahrscheinlich derselbe Algorithmus wie das e2fsprogs-Paket, fügt jedoch keine Bindestriche hinzu, sodass es für Sie möglicherweise etwas sauberer ist:

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

$ dbus-uuidgen
d17b671f98fced5649a856a54b51c9e6

Grawity fügt einen Sicherheitstipp hinzu: "DBus-UUIDs sind nicht mit RFC 4122 verwandt oder kompatibel . Außerdem verwendet dbus-uuidgen immer den Unix-Zeitstempel als die letzten 4 Bytes. Daher sind sie möglicherweise für einige Verwendungszwecke ungeeignet." (Danke, Grawity, ich hätte das auf der Manpage sehen sollen.)

Quacksalber
quelle
7
DBus-UUIDs sind nicht mit RFC 4122 verwandt oder kompatibel. Verwendet außerdem dbus-uuidgenimmer den Unix-Zeitstempel als die letzten 4 Bytes. Daher sind sie möglicherweise für einige Zwecke ungeeignet.
Grawity
Gleiches gilt auch für Fedora-25 ...
kmonsoor
20

Wenn Sie nicht von anderen ausführbaren Dateien abhängig sein möchten oder diese nicht verwenden können, finden Sie hier die reine Bash-Version von hier :

# 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
auf keinen Fall
quelle
Die TVariable kann entfernt werden und die for TSchleife kann geändert werden in: case $N in 3 | 5 | 7 | 9) printf '-';; esac(auf Wunsch in getrennten Zeilen).
Dennis Williamson
1
Ich habe dem Code unter dem Github-Link einen Kommentar hinzugefügt, der eine Version zeigt, mit caseder sowohl die ifAnweisungen als auch die innere forAnweisung entfernt werden. Es macht den Code viel ordentlicher. Beachten Sie, dass beides B%15sein sollte B%16und B%255sollte B%256.
Dennis Williamson
source <(curl url)
Stellen
19

Ich fand dieses Skript "one-liner" nützlich, wenn uuidgen nicht verfügbar ist. Dadurch wird auch die Notwendigkeit umgangen, externe Module für Perl oder Python zu installieren.

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

Getestet auf SnowLeopard, Red Hat Valhalla, Solaris 9 4/04 und neuer erfolgreich. Ich bin neugierig, ob dies zur Nicht-Einzigartigkeit neigt, aber ich bin in den letzten 10 Jahren nicht "gebissen" worden. Könnte natürlich head -1auch durch ersetzt head -_other-value_ | tail -1werden.

Erklären,

/dev/randomund /dev/urandomsind Kernel-Zufallsgeneratoren.

od (Octal Dump) hat einen Hex-Ausgangsschalter (-x), der 16 Bytes pro Zeile erzeugt.

head-n [| tail -1] (wobei n> 0 ist) extrahiert nur eine Zeile der vorherigen Ausgabe.

awkLegt fest, dass der OutputFieldSeparator überall dort, wo in der print-Anweisung ein Komma vorkommt, ein Bindestrich ist. Indem wir die Felder 2 bis 9 unabhängig voneinander angeben, steuern wir die Bindestriche und entfernen den Index- / Versatzzähler, der jeder Ausgabezeile das Präfix "od" voranstellt.

Das Ergebnis ist ein Muster aus 8-4-4-4-12Kleinbuchstaben a-f0-9.

993bb8d7-323d-b5ee-db78-f976a59d8284
Dan
quelle
1
Brillant! nur eine einzige Zeile ohne Abhängigkeiten, BSD / MacOS-kompatibel ... great
Dinigo
Verwenden Sie NICHT "tail -1". Wenn Sie nur "od -x / dev / urandom" für sich ausführen, wird dies auf unbestimmte Zeit fortgesetzt und es werden kontinuierlich mehr Zeilen mit Zufallsdaten erzeugt. "tail -1" kann einfach für immer dort sitzen und auf die "letzte" Zeile warten. Ansonsten ist es eine gute Lösung.
UncaAlby
Bitte beachten Sie, dass tail nur in der "Erklärung" als optionaler Parameter angegeben wird, wenn die Anzahl der von head ausgegebenen Zeilen größer als eins ist. Es soll sichergestellt werden, dass awk eine einzige Zeile mit 16 Bytes empfängt und nicht Teil des ursprünglichen Befehls ist. Die von od zu führende Rohrleitung desinfiziert bereits den Ausgang für die Rohrleitung zum Heck -1. Meiner Erfahrung nach wartet der Schwanz nur mit einem -f-Argument für immer. Ich entschuldige mich, wenn die Erklärung nicht klar war, wo es heißt, dass die Verwendung von tail -1 nur notwendig ist, wenn die Ausgabe von head mehr als eine Zeile erzeugt.
Dan
2
Sie nicht verwenden diese, verletzt es vollständig die UUID - Spezifikation. Nur UUIDs der Version 4 dürfen so zufällig sein.
14.
3
@jlh Ich bin nicht sicher, warum diese Frage gesperrt wurde, aber hier ist eine feste Version, die diesen Ansatz UUID-v4-konform macht: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

Nur damit Python nicht ausgelassen wird:

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

So verwenden Sie es in der Shell:

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

Informationen zu den Arten von UUIDS, die generiert werden können, finden Sie in der UUID der Python-Dokumentation .

Um eine systemd-Rechner-ID-kompatible Datei auf einem Nicht-systemd-Rechner zu generieren, können Sie Python folgendermaßen verwenden:

python -c 'import re; import uuid; print re.sub("-","",str(uuid.uuid4()))' \
 > /etc/machine-id
Davey
quelle
ist uuid ein eingebautes?
Alexander Mills
Hat Python jemals funktioniert? Ich bekomme diese `Datei" <string> ", Zeile 1 import uuid; print uuid.uuid1 () ^ SyntaxError: ungültige Syntax `
Alexander Mills
1
Verwenden Sie python3 -c "import uuid; print(uuid.uuid4())"für Python3
Abdusco
11

Perl stellt eine UUID-Bibliothek bereit, die auf dem e2fsprogsPaket basiert . Auf meinem Debian-System ist es das libuuid-perlPaket. Hier ist ein Beispiel für einen Einzeiler. siehe man uuidfür mehr:

$ 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

Dies wäre trivial, um ein Shellscript mit Backticks oder $()Notation zu ergänzen :

#!/bin/bash
# ...do some stuff
$myvar = $(perl -e 'use UUID;  UUID::generate($uuid);  UUID::unparse($uuid, $string);  print "$string";')
# ...do some more stuff
Quacksalber
quelle
+1 - Hilf mir sehr!
rafa.ferreira
1

Ich habe eine kleine Bash-Funktion mit Python geschrieben, um eine beliebige Anzahl von UUIDs in großen Mengen zu generieren:

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

Wenn Sie Kleinbuchstaben bevorzugen, ändern Sie:

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

Zu:

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

Sehen Sie sich die OSSP-UUID-Bibliothek ( http://www.ossp.org/pkg/lib/uuid/ ) an und installieren Sie sie. Einige Projekte bieten es als Option an (zB PostgreSQL). Die UUIDs von Version 3 und Version 5 wurden ordnungsgemäß verarbeitet , was über das hinausging, was meine installierte Bibliothek (z. B. e2fsprogs) verarbeiten konnte. Glücklicherweise hat openSUSE es in einem der Hauptrepos. Eine Version mit Windows (zB Cygwin) oder MySQL zum Laufen zu bringen, war ein Problem. Anscheinend ist es an der Zeit, auf Linux / PostgreSQL / Python umzusteigen (und ich mochte die SQLyog-GUI für MySQL / MariaDB so sehr), da ich wirklich UUIDs der Versionen 3 und 5 benötige.

user2351170
quelle
Stimme voll und ganz zu! Für meinen Anwendungsfall war es perfekt, da es auch Namespaces über den -v3 ns:URL custom-dataSeeding-Mechanismus unterstützt.
Roberto Andrade
1

Ich bin mir sicher, dass einige hier ankommen werden und nur nach einer einfachen Möglichkeit suchen, eine eindeutige ID zur Verwendung in ihren Skripten zu generieren, und es muss keine echte UUID sein.

In diesem Fall können Sie einfach Folgendes tun, wodurch eine sekundengenaue ID generiert wird. Wenn Sie diese also mehrmals innerhalb einer Sekunde ausführen, erhalten Sie immer noch dasselbe Ergebnis.

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

generiert ausgehend von der aktuellen Systemzeit IDs wie die folgenden:

U1454423662

HINWEIS: Wenn Sie unter Linux arbeiten oder Coreutils auf einem Mac installiert haben, können Sie Folgendes verwenden, um eine eindeutige ID für die Nanosekunde zu generieren:

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

oder wenn Sie eine Python-basierte Lösung bis zur Nanosekunde bevorzugen, die fast überall funktionieren sollte, führen Sie Folgendes aus:

MYUID=U$(python -c'import time; print repr(time.time())')
echo $MYUID
Brad Parks
quelle
1
Dies ist insgesamt eine sehr schlechte Praxis. Moderne Computer sind perfekt in der Lage, viele Dinge parallel auszuführen und serielle Aufgaben schnell zu erledigen. Diese ID ist jedoch für alle Aufrufe innerhalb einer Sekunde identisch. Ganz zu schweigen von anderen Computern, auf denen dieses Skript gleichzeitig ausgeführt wird. Eine bessere, aber immer noch nicht großartige Option wäre mktemp -uwie in MYID="$(mktemp -u)". Wenn Sie es sich leisten können, leere temporäre Dateien bis zum Neustart -uMYID="$(mktemp)"
Chris Harrington
Hey ... gute Punkte für das Einzige, was bis zum zweiten Punkt einzigartig ist ... Ich füge oben ein paar Anmerkungen hinzu ...
Brad Parks
1

Dieser Thread mit seinen vielfältigen Beispielen hat mir wirklich geholfen. Ich benötige häufig UUID-Funktionen aus verschiedenen Umgebungen. Und obwohl ich die reinen Bash-Beispiele liebe, ist es manchmal bequemer, eine Bibliothek in einer anderen Sprache zu verwenden.

Ruby (1.9.3+) verfügt über das integrierte SecureRandom-Modul, das eine Reihe nützlicher Hash- und ID-Funktionen enthält. Von der Bash Cli aus können Sie dies tun.

ruby -r securerandom -e 'puts SecureRandom.uuid'
wbr
quelle
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
quelle
3
Ein bisschen mehr Erklärung würde Ihre Antwort helfen
Dave M
x = od -X -A n /dev/random | head -1 | cut -c3-38 gibt das unten an: 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, der nach vielen Jahren wieder Bash macht, ist sehr am Rande meines derzeitigen Wissens. Hoffe, dass es ein bisschen hilft, es zu brechen. Prost, andyfff
andyfff
-1

Wenn Sie Java 10 verwenden.

$ jshell
jshell> import java.util.*
jshell> String id = UUID.randomUUID().toString();
amit
quelle
Java 10 ist keine Bash.
Kasperd
Ich habe nur ein Beispiel gegeben, wie schnell er eine UUID auf dem Terminal generieren kann, ohne ein Java-Programm auszuführen. Die Leute gaben ein Beispiel für die Verwendung von dbus-uuidgen und uuidgen . Was ist falsch an der Verwendung von jshell?
Am
1
@amit der Punkt ist, dass Sie ein Beispiel angeben müssen, in dem Bash- Skripte jshellverwendet werden können , und nicht als interaktiver Befehl . Das wird im ursprünglichen Beitrag sehr deutlich.
Samveen
Wenn Sie dies auflisten müssen, können Sie es tun. echo "System.out.println(java.util.UUID.randomUUID().toString())" | /Library/Java/JavaVirtualMachines/openjdk-11.0.1.jdk/Contents/Home/bin/jshell -s | grep -v ">" Aber es ist viel langatmiger als uuidgen.
mlk