Jak utworzyć UUID w bash?

185

W Javie można utworzyć losowy UUID :

UUID uuid = UUID.randomUUID();

Jak to zrobić w Bash?

raoulsson
źródło

Odpowiedzi:

225

Zobacz uuidgenprogram, który jest częścią pakietu e2fsprogs .

Zgodnie z tym , libuuidjest teraz częścią util-linux, a włączenie do e2fsprogs jest stopniowo wycofywane. Jednak w nowych systemach Ubuntu uuidgenjest teraz w uuid-runtimepakiecie.

Aby utworzyć identyfikator UUID i zapisać go w zmiennej:

uuid=$(uuidgen)

W moim systemie Ubuntu znaki alfabetu są wypisywane małymi literami, a w systemie OS X - dużymi literami (dzięki Davidowi za zwrócenie na to uwagi w komentarzu).

Aby przełączyć na wszystkie wielkie litery (po wygenerowaniu jak wyżej):

uuid=${uuid^^}

Aby przełączyć na wszystkie małe litery:

uuid=${uuid,,}

Jeśli na przykład masz dwa identyfikatory UUID i chcesz je porównać w Bash, ignorując ich wielkość, możesz wykonać tolower()porównanie stylów w następujący sposób:

if [[ ${uuid1,,} == ${uuid2,,} ]]
Dennis Williamson
źródło
7
hej, nie fair! moje e2fsprogs nie były z tym związane! chcę jeden, skąd go wziąć? (aktualizacja: ahhh ... debian wrzuca go do uuid-runtimepakietu bez wyraźnego powodu ... +1 do ciebie)
quack quixote
uuidgen jest wbudowany we FreeBSD. nie zawsze jest w pakiecie e2fsprogs.
Dobra osoba
1
@Rob: Aby odpowiedzieć na pierwotne pytanie, dotyczy etykiet dysków .
Dennis Williamson,
2
Zauważyłem, że uuidgen na Macu emituje wielkie litery, a na Ubuntu (uuidgen z util-linux 2.20.1) małymi literami. Skąd ta różnica? Również Ubuntu wymienia, skąd pochodzi to narzędzie, ale na Macu nie ma informacji o wersji ani pakietu, z którego pochodzi.
David
1
@David: Uważam, że jest to część podstawowego systemu operacyjnego OS X. Nie mam pojęcia, dlaczego jedna jest wielka, a druga mała. To naprawdę nie ma znaczenia, ponieważ oba reprezentują prawidłowe znaki szesnastkowe ( echo -e 'f\nF' | grep '[[:xdigit:]]'wypisują obie linie). Jeśli ma to dla Ciebie znaczenie i masz Bash 4, możesz to zrobić, aby małe litery: uuid=$(uuidgen); uuid=${uuid,,}lub to, aby było wielkie: uuid=$(uuidgen); uuid=${uuid^^}lub coś w tym tolower()stylu, aby wykonać test stylu:if [[ ${uuid1,,} == ${uuid2,,} ]]
Dennis Williamson
168

Aby dodać różnorodność bez dodawania zewnętrznych zależności, w systemie Linux możesz:

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

Aby propagować złe praktyki na FreeBSD , w warstwie kompatybilności z linuksem (linuxulator?),

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

Bibliografia:

Samveen
źródło
19
To jest niesamowite.
Tom O'Connor,
3
Należy tego unikać, ponieważ jest wysoce nieprzenośny (chociaż materiały FreeBSD / kompatybilny / linux / proc / sys / kernel / random / uuid dla źle napisanych aplikacji)
Good Person
1
Idealnie pasuje do użytku w obrazie initrd
Maximilian
2
To powinna być najlepsza odpowiedź!
dguerri
6
To lepsza odpowiedź dla naprawdę minimalnych konfiguracji, takich jak kontener Docker.
jacderida
34

Ze względu na kompletność ... Jest także generator UUID z dbuspakietem na Debianie. Tęskniłem za rozglądaniem się wcześniej. Prawdopodobnie jest to ten sam algorytm co pakiet e2fsprogs, ale nie dodaje myślników, więc może być dla ciebie trochę czystszy:

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

$ dbus-uuidgen
d17b671f98fced5649a856a54b51c9e6

Grawity dodaje wskazówkę dotyczącą bezpieczeństwa: „UUID DBus nie są powiązane ani zgodne z RFC 4122. Poza tym dbus-uuidgen zawsze używa uniksowego znacznika czasu jako ostatnich 4 bajtów. Więc mogą być nieodpowiednie dla niektórych zastosowań.” (Dzięki, Grawity, powinienem to zauważyć na stronie podręcznika.)

quack quixote
źródło
7
Identyfikatory UUID DBus nie są powiązane ani zgodne z RFC 4122. Poza tym dbus-uuidgenzawsze używa uniksowego znacznika czasu jako ostatnich 4 bajtów. Mogą więc nie nadawać się do niektórych zastosowań.
grawity
to samo działa również na Fedorze-25 ...
kmonsoor
20

Jeśli nie chcesz polegać na innych wykonywalnych lub nie można ich użyć, tutaj jest czysta wersja bash od tutaj :

# 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
nie ma mowy
źródło
TZmienna może być wyeliminowana, a for Tpętla może zostać zmienione na: case $N in 3 | 5 | 7 | 9) printf '-';; esac(podzielone na oddzielne linie od preferencji).
Dennis Williamson
1
Dodałem komentarz do kodu w linku github pokazujący wersję używającą casedo wyeliminowania ifinstrukcji, a także instrukcję wewnętrzną for. To sprawia, że ​​kod jest znacznie prostszy. Zauważ, że oba B%15powinny być B%16i B%255powinny być B%256.
Dennis Williamson
umieść go online pod adresem URL, aby ludzie mogli go zdobyć i wypróbować, source <(curl url)czy cokolwiek innego
MrCholo
19

Uważam, że ten skrypt „one-liner” jest użyteczny tam, gdzie uuidgen nie jest dostępny. Pomija to również konieczność instalowania zewnętrznych modułów dla Perla lub Pythona.

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

Testy przeprowadzone na SnowLeopard, Red Hat Valhalla, Solaris 9 4/04 i nowszych. Jestem ciekawy, czy jest to podatne na wyjątkowość, ale przez ostatnie 10 lat nie byłem „trochę przygnębiony”. Oczywiście head -1można je również zastąpić head -_other-value_ | tail -1.

Wytłumaczyć,

/dev/randomi /dev/urandomsą losowymi generatorami jądra.

od (zrzut ósemkowy) ma przełącznik wyjścia szesnastkowego (-x) wytwarzający 16 bajtów na linię.

head-n [| tail -1] (gdzie n> 0) wyodrębnia tylko jeden wiersz poprzedniego wyniku.

awkustawia OutputFieldSeparator jako myślnik wszędzie tam, gdzie występuje przecinek w instrukcji print. Określając pola 2-9 niezależnie, kontrolujemy łączniki i usuwamy licznik indeksu / offsetu, przed którym „od” poprzedza każdą linię wyniku.

Rezultatem jest wzór 8-4-4-4-12małych liter a-f0-9.

993bb8d7-323d-b5ee-db78-f976a59d8284
Dan
źródło
1
Znakomity! tylko jedna linia bez żadnych zależności, kompatybilna z BSD / macOS ... świetnie
dinigo
Czy nie korzystaj z „ogonem -1”. Jeśli uruchomisz po prostu polecenie „od -x / dev / urandom”, będzie ono działać w nieskończoność, stale wytwarzając więcej wierszy losowych danych. „tail -1” może po prostu siedzieć tam na zawsze i czekać na „ostatnią” linię. W przeciwnym razie jest to dobre rozwiązanie.
UncaAlby
Uwaga: ogon występuje tylko w „objaśnieniu” jako parametr opcjonalny, gdy liczba linii wyprowadzanych przez głowę jest większa niż jeden. Tam, aby zapewnić otrzymanie pojedynczej linii 16 bajtów przez awk i nie jest częścią oryginalnej komendy. Rura do głowicy od od już dezynfekuje wyjście dla orurowania do ogona -1. Z mojego doświadczenia wynika, że ​​jedynym czasem, w którym ogon czeka wiecznie, jest argument -f. Przepraszam, jeśli wyjaśnienie nie było jasne, gdzie stwierdza, że ​​użycie ogona -1 jest konieczne tylko wtedy, gdy wyjście głowy wytwarza więcej niż jedną linię.
dan
2
Czy nie to wykorzystać, to zupełnie niezgodny ze specyfikacją UUID. Tylko UUID w wersji 4 mogą być losowe w ten sposób.
jlh
3
@jlh Nie jestem pewien, dlaczego to pytanie zostało zablokowane, ale oto poprawiona wersja, która sprawia, że ​​to podejście jest zgodne z 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

Właśnie dlatego python nie czuje się wykluczony:

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

Aby użyć go w powłoce:

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

Zobacz UUID dokumentacji Pythona, aby dowiedzieć się, jakie rodzaje UUIDS można wygenerować.

Aby wygenerować plik zgodny z identyfikatorem systemowym komputera na komputerze niesystemowym, możesz użyć Pythona, aby to zrobić w ten sposób:

python -c 'import re; import uuid; print re.sub("-","",str(uuid.uuid4()))' \
 > /etc/machine-id
davey
źródło
czy UUID jest wbudowany?
Alexander Mills
Czy python kiedykolwiek działał? Dostaję ten „Plik” <ciąg> ”, wiersz 1 import uuid; print uuid.uuid1 () ^ Błąd składni: nieprawidłowa składnia `
Alexander Mills
1
Użyj python3 -c "import uuid; print(uuid.uuid4())"dla python3
abdusco
11

Perl udostępnia bibliotekę UUID na podstawie e2fsprogspakietu. W moim systemie Debian jest to libuuid-perlpakiet. Oto przykładowy jeden wiersz; zobacz man uuidwięcej:

$ 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

Byłoby trywialne dodawanie do shellscript za pomocą odwrotnych $()znaków lub notacji:

#!/bin/bash
# ...do some stuff
$myvar = $(perl -e 'use UUID;  UUID::generate($uuid);  UUID::unparse($uuid, $string);  print "$string";')
# ...do some more stuff
quack quixote
źródło
+1 - bardzo mi pomóż!
rafa.ferreira
1

Napisałem małą funkcję Bash, używając Pythona do generowania dowolnej liczby identyfikatorów UUID:

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

Jeśli wolisz małe litery, zmień:

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

Do:

python -c 'import uuid; print("\n".join([str(uuid.uuid4()) for x in range('"$count"')]))'
Będzie
źródło
1

Proszę spojrzeć na bibliotekę UUID OSSP ( http://www.ossp.org/pkg/lib/uuid/ ) i rozważyć zainstalowanie jej. Niektóre projekty oferują to jako opcję (np. PostgreSQL). Prawidłowo obsługuje UUID wersji 3 i wersji 5 , co wykraczało poza możliwości mojej zainstalowanej biblioteki (np. E2fsprogs). Na szczęście openSUSE ma to w jednym z głównych repozytoriów. Uzyskiwanie wersji do pracy w systemie Windows (np. Cygwin) lub MySQL było bujakiem. Wygląda na to, że nadszedł czas, aby przejść na Linux / PostgreSQL / Python (i bardzo podobało mi się GUI SQLyog na MySQL / MariaDB), ponieważ naprawdę potrzebuję UUID v3 i v5.

użytkownik2351170
źródło
Zgadzam się całkowicie! Dla mojego przypadku użycia był idealny, ponieważ obsługuje także przestrzeń nazw za pośrednictwem -v3 ns:URL custom-datamechanizmu inicjującego.
Roberto Andrade,
1

Jestem pewien, że niektórzy tu przybędą i właśnie szukają łatwego sposobu na wygenerowanie unikalnego identyfikatora do użycia w swoich skryptach i nie musi to być prawdziwy UUID.

Jeśli tak, możesz po prostu wykonać następujące czynności, które wygenerują identyfikator, który jest unikalny aż do sekundy - więc jeśli uruchomisz to wiele razy w ciągu sekundy, nadal otrzymasz ten sam wynik.

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

wygeneruje identyfikatory takie jak następujące na podstawie bieżącego czasu systemowego:

U1454423662

UWAGA: Jeśli korzystasz z systemu Linux lub masz Coreutils zainstalowany na komputerze Mac, możesz użyć następujących opcji, aby wygenerować unikalny identyfikator nanosekundy:

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

lub jeśli wolisz rozwiązanie oparte na pythonie niż nanosekundę, które powinno działać prawie wszędzie, uruchom:

MYUID=U$(python -c'import time; print repr(time.time())')
echo $MYUID
Brad Parks
źródło
1
Jest to ogólnie bardzo zła praktyka. Współczesne komputery są w pełni zdolne do równoległego uruchamiania wielu rzeczy i szybkiego wykonywania zadań szeregowych, ale ten identyfikator będzie identyczny dla wszystkich wywołań z dokładnością do sekundy. Nie wspominając o żadnym innym komputerze z tym skryptem w tym samym czasie. Lepsza, ale wciąż nie świetna opcja byłaby mktemp -ujak w MYID="$(mktemp -u)". Jeśli możesz sobie pozwolić na tworzenie pustych plików tymczasowych aż do ponownego uruchomienia, upuść -u:MYID="$(mktemp)"
Chris Harrington
Hej ... dobre punkty za jedyne w drugim punkcie ... Dodam kilka notatek powyżej ...
Brad Parks
1

Ten wątek, z różnymi przykładami, był dla mnie bardzo przydatny. Często potrzebuję funkcji UUID z wielu różnych środowisk. I chociaż uwielbiam przykłady czystej bashu, czasem wygodniej jest używać biblioteki z innego języka.

Dla dokładności ruby ​​(1.9.3+) ma wbudowany moduł SecureRandom zawierający szereg użytecznych funkcji skrótu i ​​identyfikatora. Z bash cli możesz to zrobić.

ruby -r securerandom -e 'puts SecureRandom.uuid'
wbr
źródło
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
źródło
3
Trochę więcej wyjaśnień pomoże ci w odpowiedzi
Dave M
x = od -X -A n /dev/random | head -1 | cut -c3-38 daje to poniżej 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., wracając do gry po wielu latach, jest to bardzo na granicy mojej obecnej wiedzy. Nadzieja, że ​​się trochę zepsuje, pomaga. na zdrowie, andyfff
andyfff
-1

Jeśli używasz Java 10.

$ jshell
jshell> import java.util.*
jshell> String id = UUID.randomUUID().toString();
amit
źródło
Java 10 nie jest bash.
kasperd
Podałem tylko przykład, jak szybko może wygenerować UUID na terminalu bez uruchamiania programu Java. Ludzie podali przykład użycia dbus-uuidgen i uuidgen . Co jest złego w korzystaniu z jshell?
amit
1
@ Chodzi o to, że musisz podać przykład, w którym jshellmożna go używać w skryptach bash , a nie jako polecenie interaktywne . Jest to bardzo jasne w oryginalnym poście.
Samveen
Jeśli musisz zrobić coś z tej listy, możesz to zrobić echo "System.out.println(java.util.UUID.randomUUID().toString())" | /Library/Java/JavaVirtualMachines/openjdk-11.0.1.jdk/Contents/Home/bin/jshell -s | grep -v ">" Ale jest to o wiele bardziej skomplikowane niż uuidgen.
mlk