Як створити UUID в bash?


185

У Java можна створити випадковий UUID :

UUID uuid = UUID.randomUUID();

Як це зробити в Bash?

Відповіді:


225

Дивіться uuidgenпрограму, яка є частиною пакету e2fsprogs .

Відповідно до цього , libuuidзараз є частиною util-linux, і включення в e2fsprogs припиняється. Однак, для нових систем Ubuntu, uuidgenтепер є в uuid-runtimeкомплекті.

Щоб створити uuid та зберегти його у змінній:

uuid=$(uuidgen)

У моїй системі Ubuntu альфа-символи виводяться як малі регістри, а в моїй системі X X вони виводяться у верхньому регістрі (спасибі Девіду, що вказав це у коментарі).

Щоб переключитися на верхній регістр (після його створення, як описано вище):

uuid=${uuid^^}

Щоб переключитися на всі малі регістри:

uuid=${uuid,,}

Якщо, наприклад, у вас є два UUID, і ви хочете порівняти їх у Bash, ігноруючи їхній випадок, ви можете зробити tolower()порівняння стилів, як це:

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

7
Гей, не чесно! мої e2fsprogs не були з цим! я хочу одного, де я його беру? (оновлення: а-а-а ... Debian вставляє його в uuid-runtimeпакет без видимих ​​причин ... +1 вам)
шарлатаний кіхот

uuidgen поставляється вбудованим на freeBSD. це не завжди в пакеті e2fsprogs.
Добра людина

1
@Rob: Щоб відповісти на своє первісне запитання, це етикетки диска .
Денніс Вільямсон

2
Я помічаю, що uuidgen на Mac випромінюється у всіх великих літерах, а на Ubuntu (uuidgen від util-linux 2.20.1) у всіх малих літерах. Чому різниця? Також Ubuntu перераховував, звідки прийшов інструмент, але на Mac, немає інформації про версію, а також від якого пакета.
Девід

1
@David: Я вважаю, що це частина базової операційної системи на OS X. Я поняття не маю, чому один верхній регістр, а другий нижній. Це насправді не має значення, оскільки будь-який представляє дійсні шістнадцяткові символи ( echo -e 'f\nF' | grep '[[:xdigit:]]'виводить обидва рядки). Якщо для вас це важливо, і у вас є Bash 4, ви можете зробити це, щоб зробити його нижчим регістром: uuid=$(uuidgen); uuid=${uuid,,}або це зробити його uuid=$(uuidgen); uuid=${uuid^^}великим регістром: або щось за цими напрямками зробити tolower()тест на стиль:if [[ ${uuid1,,} == ${uuid2,,} ]]
Денніс Вільямсон,

168

Щоб додати різноманітність без додавання зовнішніх залежностей, в Linux ви можете:

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

Щоб поширювати погані практики на FreeBSD під шаром сумісності Linux (linuxulator?),

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

Список літератури:


19
Це круто.
Том О'Коннор

3
Цього слід уникати, оскільки він є дуже не портативним (хоча FreeBSD постачає / compat / linux / proc / sys / kernel / random / uuid для погано написаних додатків)
Good Person

1
Він ідеально підходить для використання всередині зображення initrd
Максиміліан

2
Це має бути найкращою відповіддю!
dguerri

6
Це краща відповідь для дійсно мінімальних налаштувань, як контейнер Docker.
jacderida

34

Тільки задля повноти ... Також dbusна Debian встановлений генератор UUID . Я пропустив це, озираючись раніше. Це, мабуть, той самий алгоритм, що і пакет e2fsprogs, але він не додає тире, тому він може бути трохи чистішим для вас:

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

$ dbus-uuidgen
d17b671f98fced5649a856a54b51c9e6

Grawity додає підказку щодо безпеки: "UUIDs DBus не пов'язані або сумісні з RFC 4122. Крім того, dbus-uuidgen завжди використовує часову позначку Unix як останні 4 байти. Тому вони можуть бути непридатними для деяких застосувань." (Дякую, Грейвіті, я повинен був це помітити на сторінці сторінки.)


7
UUIDs DBus не пов'язані або сумісні з RFC 4122. Крім того, dbus-uuidgenзавжди використовується часова мітка Unix як останні 4 байти. Тому вони можуть бути непридатними для деяких цілей.
grawity

ті ж роботи над Fedora-25 теж ...
kmonsoor

20

Якщо ви не хочете залежати від інших виконуваних файлів, або ви не можете використовувати їх, тут чиста версія Баша від тут :

# 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

TЗмінна може бути усунена , і for Tцикл може бути змінений на: case $N in 3 | 5 | 7 | 9) printf '-';; esac(розбиті на окремі рядки , якщо краще).
Денніс Вільямсон

1
Я додав коментар до коду за посиланням github, що показує версію, яка використовує caseдля усунення ifоператорів, а також внутрішній forвислів. Це робить код набагато охайнішим. Зверніть увагу , що обидва B%15повинні бути B%16і B%255повинні бути B%256.
Денніс Вільямсон

розмістіть його в Інтернеті за URL-адресою, щоб люди могли його source <(curl url)
шукати

19

Я знайшов цей сценарій "однолінійним" корисним там, де uuidgen недоступний. Це також обминає будь-яку необхідність встановлення зовнішніх модулів для Perl або Python.

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

Випробувано на SnowLeopard, Red Hat Valhalla, Solaris 9 4/04 та новіших з успіхом. Мені цікаво, якщо це схильне до неповторності, але мене не «покусали» за останні 10 років. Звичайно, head -1можна було б замінити head -_other-value_ | tail -1теж.

Пояснити,

/dev/randomі /dev/urandomє генераторами випадкових ядер.

od (восьмеричний дамп) має шістнадцятковий вихідний перемикач (-x), що створює 16 байт на рядок.

head-н ​​[| хвіст -1] (де n> 0) витягує лише один рядок попереднього виводу.

awkвстановлює OutputFieldSeparator дефісом скрізь, коли в операторі друку виникає кома. Вказуючи поля 2-9 незалежно, ми керуємо дефісами і знімаємо лічильник індексів / зсувів, який 'od' приєднує кожен рядок виводу.

В результаті виходить візерунок 8-4-4-4-12малих символів a-f0-9.

993bb8d7-323d-b5ee-db78-f976a59d8284

1
Блискуче! просто один рядок без залежностей, сумісний BSD / macOS ... чудово
dinigo

Як НЕ використовувати «хвіст -1». Якщо ви запускаєте лише "od -x / dev / urandom" сам по собі, він триває нескінченно, безперервно створюючи більше рядків випадкових даних. "хвіст -1" може просто сидіти там вічно і чекати "останнього" рядка. В іншому випадку це хороше рішення.
UncaAlby

Зверніть увагу, хвіст міститься лише в "поясненні" як необов'язковий параметр, коли кількість рядків, виведених головою, більше одиниці. Там для забезпечення отримання єдиного рядка з 16 байтів awk, і не є частиною вихідної команди. Труба до головки од вже санітує вихід для трубопроводів до хвоста -1. На мій досвід, єдиний раз, коли хвіст чекає вічно, це аргумент -f. Прошу вибачення, якщо в поясненні не було зрозуміло, де зазначено, що використання хвоста -1 необхідне лише тоді, коли на виході голови утворюється більше одного рядка.
дан

2
Ви НЕ використовувати це, вона повністю порушує специфікацію UUID. Лише UUID версії 4 може бути випадковим таким.
jlh

3
@jlh Я не впевнений, чому це питання було заблоковано, але ось фіксована версія, яка робить такий підхід 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

Просто так пітон не відчуває себе осторонь:

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

Щоб використовувати його в оболонці:

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

Дивіться UUID документації Python щодо типів UUIDS, які можна генерувати.

Для створення файлу, сумісного з системним ідентифікатором на несистемній машині, ви можете використовувати python, щоб зробити це таким чином:

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

uuid вбудований?
Олександр Міллз

Чи працював пітон коли-небудь? Я отримую цей файл "<string>", рядок 1 імпорту uuid; print uuid.uuid1 () ^ SyntaxError: неправильний синтаксис `
Олександр Міллз

1
Використовуйте python3 -c "import uuid; print(uuid.uuid4())"для python3
abdusco

11

Perl надає бібліотеку UUID на основі e2fsprogsпакету. У моїй системі Debian це libuuid-perlпакет. Ось приклад однолінійного; см man uuidбільше:

$ 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

Це доцільно додати до оболонки із зворотними посиланнями чи $()позначеннями:

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

+1 - Допоможи мені багато!
rafa.ferreira


1

Я написав невелику функцію Bash за допомогою Python для генерації довільної кількості 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"')]))'
}

Якщо ви віддаєте перевагу малі літери, змініть:

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

1

Перегляньте бібліотеку UUID OSSP ( http://www.ossp.org/pkg/lib/uuid/ ) та подумайте про її встановлення. Деякі проекти пропонують його як варіант (наприклад, PostgreSQL). Він належним чином обробляє UUID версії 3 та версії 5 , що виходило за рамки моєї встановленої бібліотеки (наприклад, e2fsprogs). На щастя, openSUSE має його в одному з головних репостів. Налаштування версії для роботи з Windows (наприклад, Cygwin) або MySQL було недоліком. Схоже, настав час перейти на Linux / PostgreSQL / Python (і мені так сподобався графічний інтерфейс SQLyog до MySQL / MariaDB), оскільки мені дуже потрібні U3 V3 та V5.


Погодьтеся повністю! Для мого використання це було ідеально, оскільки він також підтримує пропуск імен через -v3 ns:URL custom-dataмеханізм висіву.
Роберто Андраде

1

Я впевнений, що деякі приїдуть сюди, і просто шукають простий спосіб генерувати унікальний ідентифікатор для використання у своїх сценаріях, і це не потрібно, щоб бути справжнім UUID.

Якщо це так, ви можете просто виконати наступне, що створить унікальний ідентифікатор до другого - так що, якщо ви виконаєте це кілька разів протягом секунди, ви все одно отримаєте той самий результат.

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

буде генерувати ідентифікатори, такі як наступні, виходячи з поточного системного часу:

U1454423662

ПРИМІТКА. Якщо ви перебуваєте в Linux або інстальовано Coreutils на mac, ви можете використовувати наступне для створення унікального ідентифікатора для наносекунди:

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

або якщо ви віддаєте перевагу рішення на основі пітона до наносекунди, яке має працювати майже скрізь, запустіть:

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

1
Це загалом дуже погана практика. Сучасні комп’ютери цілком здатні паралельно виконувати багато речей і швидко виконувати послідовні завдання, але цей ідентифікатор буде ідентичним для будь-яких викликів, що знаходяться в межах однієї секунди іншої. Не кажучи вже про будь-які інші комп’ютери, що працюють із цим сценарієм одночасно. Кращий, але все ж не дуже великий варіант був би mktemp -uяк в MYID="$(mktemp -u)". Якщо ви можете собі дозволити, щоб порожні тимчасові файли лежали до перезавантаження, киньте -u:MYID="$(mktemp)"
Кріс Харрінгтон,

Гей ... хороші моменти на єдиному унікальному для другого пункту ... Я додам кілька записок вище ...
Бред Паркс

1

Ця нитка, маючи різноманітні приклади, була мені дуже корисна. Мені часто потрібні функції uuid з різних середовищ. І хоча я люблю чисті баш-приклади, іноді зручніше використовувати бібліотеку з іншої мови.

Тож для ґрунтовності ruby ​​(1.9.3+) має вбудований модуль SecureRandom, що містить ряд корисних функцій хеш-ідентифікаторів. З bash cli, ви можете це зробити.

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
Трохи більше пояснень допоможе Ваша відповідь
Дейв М

x = od -X -A n /dev/random | head -1 | cut -c3-38 дає вам це нижче 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

Дейв М, коли я займався баштом через багато років, це дуже на краю моїх нинішніх знань. Сподівання, що її трохи зруйнувати, допомагає. ура, andyfff
andyfff

-1

Якщо ви використовуєте Java 10.

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

Java 10 не баш.
kasperd

Я просто наводив приклад того, як швидко він може генерувати UUID на терміналі без запуску програми java. Люди наводили приклад використання dbus-uuidgen та uuidgen . Що не так у використанні jshell?
Amit

1
@amit суть у тому, що вам потрібно навести приклад, де jshellможна використовувати в сценаріїх bash , а не як інтерактивну команду . Це дуже ясно в оригінальній публікації.
Самвін

Якщо вам доведеться щось із цього перелічити, ви могли б зробити. echo "System.out.println(java.util.UUID.randomUUID().toString())" | /Library/Java/JavaVirtualMachines/openjdk-11.0.1.jdk/Contents/Home/bin/jshell -s | grep -v ">" Але це набагато довше звивисто, ніж uuidgen.
млк
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.