Как создать UUID в Bash?

185

В Java можно создать случайный UUID :

UUID uuid = UUID.randomUUID();

Как это сделать в Bash?

raoulsson
источник

Ответы:

225

Смотрите uuidgenпрограмму, которая является частью пакета e2fsprogs .

Согласно этому , libuuidтеперь является частью util-linux, и включение в e2fsprogs постепенно прекращается. Тем не менее, на новых системах Ubuntu, uuidgenтеперь в uuid-runtimeпакете.

Чтобы создать uuid и сохранить его в переменной:

uuid=$(uuidgen)

В моей системе Ubuntu буквенные символы выводятся в нижнем регистре, а в моей системе OS X - в верхнем (спасибо Дэвиду за то, что он указал это в комментарии).

Чтобы переключиться на весь верхний регистр (после генерации, как указано выше):

uuid=${uuid^^}

Чтобы переключиться на все строчные буквы:

uuid=${uuid,,}

Если, например, у вас есть два UUID и вы хотите сравнить их в Bash, игнорируя их регистр, вы можете выполнить tolower()сравнение стилей следующим образом:

if [[ ${uuid1,,} == ${uuid2,,} ]]
Деннис Уильямсон
источник
7
эй, нечестно! мои e2fsprogs не пришли с этим! я хочу один, где я могу получить это? (обновление: аааа ... uuid-runtime
дебиан сунул
UUIDGEN встроен в FreeBSD. это не всегда в пакете e2fsprogs.
Хороший человек
1
@Rob: Чтобы ответить на ваш оригинальный вопрос, это для меток дисков .
Деннис Уильямсон
2
Я заметил, что uuidgen на Mac выдает все заглавные буквы, а на Ubuntu (uuidgen из util-linux 2.20.1) - все строчные. Почему разница? Также Ubuntu перечислила, откуда появился этот инструмент, но на Mac нет информации о версии и о том, из какого пакета он пришел.
Дэвид
1
@ Дэвид: Я полагаю, что это часть базовой операционной системы на 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)

Рекомендации:

Samveen
источник
19
Это круто.
Том О'Коннор
3
Этого следует избегать, поскольку он очень непереносим (хотя FreeBSD поставляет / compat / linux / proc / sys / kernel / random / uuid для плохо написанных приложений)
Good Person
1
Он идеально подходит для использования внутри образа initrd
Максимилиан
2
Это должен быть лучший ответ!
августа
6
Это лучший ответ для действительно минимальных настроек, таких как контейнер Docker.
jacderida
34

Просто для полноты ... В dbusDebian также установлен UUID-генератор с пакетом. Я пропустил это, оглядываясь раньше. Вероятно, это тот же алгоритм, что и в пакете e2fsprogs, но он не добавляет тире, поэтому он может быть немного чище для вас:

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

$ dbus-uuidgen
d17b671f98fced5649a856a54b51c9e6

Grawity добавляет совет по безопасности: «UUID DBus не связаны или не совместимы с RFC 4122. Кроме того, dbus-uuidgen всегда использует метку времени Unix в качестве последних 4 байтов. Поэтому они могут быть неподходящими для некоторых применений». (Спасибо, Гравити, я должен был это заметить на странице руководства.)

шарлатан
источник
7
UUID DBus не связаны или не совместимы с RFC 4122. Кроме того, dbus-uuidgenвсегда использует метку времени Unix в качестве последних 4 байтов. Таким образом, они могут быть непригодны для некоторых целей.
Гравитация
то же самое работает и на 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)или что-то еще
MrCholo
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-n [| tail -1] (где n> 0) извлекает только одну строку предыдущего вывода.

awkустанавливает OutputFieldSeparator как дефис везде, где в операторе печати встречается запятая. Определяя поля 2-9 независимо, мы контролируем дефисы и убираем счетчик индекса / смещения, с которым префикс 'od' ставит перед каждой строкой вывода.

Результатом является образец 8-4-4-4-12строчных букв a-f0-9.

993bb8d7-323d-b5ee-db78-f976a59d8284
Дан
источник
1
Brilliant! только одна строка без зависимостей, совместимая с BSD / macOS ... отлично
dinigo
Как НЕ использовать «хвост -1». Если вы запустите только «od -x / dev / urandom», это будет продолжаться бесконечно, непрерывно создавая больше строк случайных данных. «Хвост -1» может просто сидеть там вечно, ожидая «последней» строки. В противном случае это хорошее решение.
UncaAlby
Обратите внимание, что хвост указывается в «объяснении» только как необязательный параметр, когда количество строк, выводимых заголовком, больше единицы. Там для обеспечения получения одной строки 16 байтов по awk, и не является частью исходной команды. Труба к голове от od уже дезинфицирует вывод для трубопровода к хвосту -1. По моему опыту, единственное время, которое хвост ждет вечно, это аргумент -f. Я прошу прощения, если объяснение не было ясным, где говорится, что использование хвоста -1 необходимо только тогда, когда вывод head выдает более одной строки.
дан
2
Вы не использовать это, она полностью нарушает спецификацию UUID. Только случайный UUID версии 4 может быть случайным, как это.
июля
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}'
Стюарт П. Бентли,
14

Просто чтобы питон не чувствовал себя обделенным:

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

Чтобы использовать его в оболочке:

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

Посмотрите UUID Документации Python для типов UUIDS, которые могут быть сгенерированы.

Чтобы сгенерировать системный ID, совместимый с идентификатором компьютера, на компьютере, отличном от systemd, вы можете использовать python для этого:

python -c 'import re; import uuid; print re.sub("-","",str(uuid.uuid4()))' \
 > /etc/machine-id
Davey
источник
UUID является встроенным?
Александр Миллс
Python когда-нибудь работал? Я получаю этот файл `<строка>", строка 1 import 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

Пожалуйста, посмотрите на библиотеку OSSP UUID ( http://www.ossp.org/pkg/lib/uuid/ ) и рассмотрите возможность ее установки. Некоторые проекты предлагают его в качестве опции (например, PostgreSQL). Он правильно обрабатывает UUID версии 3 и версии 5 , что было выше того, что могла обработать моя установленная (например, e2fsprogs) библиотека. К счастью, openSUSE имеет его в одном из основных репозиториев. Получение версии для работы с Windows (например, Cygwin) или MySQL было непростым делом. Похоже, пришло время перейти на Linux / PostgreSQL / Python (и мне так понравился графический интерфейс SQLyog для MySQL / MariaDB), поскольку мне действительно нужны UUID v3 и v5.

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

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

Если это так, вы можете просто сделать следующее, что сгенерирует уникальный идентификатор с точностью до секунды - так что если вы запустите это несколько раз в течение секунды, вы все равно получите тот же результат.

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

будет генерировать идентификаторы, подобные следующим, основываясь на текущем системном времени:

U1454423662

ПРИМЕЧАНИЕ. Если вы работаете в Linux или Coreutils установлены на Mac, вы можете использовать следующее для генерации уникального идентификатора наносекунды:

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

или если вы предпочитаете решение на основе Python вплоть до наносекунды, которое должно работать почти везде, запустите:

MYUID=U$(python -c'import time; print repr(time.time())')
echo $MYUID
Брэд Паркс
источник
1
Это в целом очень плохая практика. Современные компьютеры вполне способны выполнять много вещей параллельно и быстро выполнять последовательные задачи, но этот идентификатор будет одинаковым для любых вызовов, которые находятся в пределах одной секунды от другой. Не говоря уже о других компьютерах, на которых запущен этот скрипт одновременно. Лучше, но все же не очень хороший вариант, mktemp -uкак в MYID="$(mktemp -u)". Если вы можете позволить себе хранить временные файлы до перезагрузки, оставьте -u:MYID="$(mktemp)"
Крис Харрингтон
Эй ... хорошие моменты по единственному второму пункту ... Я добавлю несколько заметок выше ...
Брэд Паркс
1

Эта тема с ее разнообразными примерами была очень полезна для меня. Мне часто нужны функции uuid из разных сред. И хотя мне нравятся чистые примеры bash, иногда удобнее использовать библиотеку на другом языке.

Так что для большей полноты, ruby ​​(1.9.3+) имеет встроенный модуль SecureRandom, содержащий ряд полезных хеш-функций и функций id. Вы можете сделать это из Bash Cli.

ruby -r securerandom -e 'puts SecureRandom.uuid'
WBR
источник
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
источник
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
Дэйв М, вернувшийся после многих лет работы в bash, это очень близко к моим нынешним знаниям. Надеюсь, что сломать его немного поможет. ура, andyfff
andyfff
-1

Если вы используете Java 10.

$ jshell
jshell> import java.util.*
jshell> String id = UUID.randomUUID().toString();
Амит
источник
Java 10 не является Bash.
Касперд
Я просто привел пример того, как быстро он может генерировать 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.
MLK