Como criar um UUID no bash?

185

Em Java, é possível criar um UUID aleatório :

UUID uuid = UUID.randomUUID();

Como fazer isso no Bash?

raoulsson
fonte

Respostas:

225

Veja o uuidgenprograma que faz parte do pacote e2fsprogs .

De acordo com isso , libuuidagora faz parte do util-linux e a inclusão no e2fsprogs está sendo eliminada. No entanto, nos novos sistemas Ubuntu, uuidgenagora está no uuid-runtimepacote.

Para criar um uuid e salvá-lo em uma variável:

uuid=$(uuidgen)

No meu sistema Ubuntu, os caracteres alfa são impressos em minúsculas e, no sistema OS X, em maiúsculas (obrigado a David por apontar isso em um comentário).

Para alternar para todas as letras maiúsculas (depois de gerá-las como acima):

uuid=${uuid^^}

Para alternar para todas as minúsculas:

uuid=${uuid,,}

Se, por exemplo, você tiver dois UUIDs e quiser compará-los no Bash, ignorando o caso deles, poderá fazer uma tolower()comparação de estilos como esta:

if [[ ${uuid1,,} == ${uuid2,,} ]]
Dennis Williamson
fonte
7
ei, não é justo! meus e2fsprogs não vieram com isso! eu quero um, onde eu consigo? (actualização: ahhh ... debian fura-lo no uuid-runtimepacote sem razão aparente ... +1 para você)
quack quixote
O uuidgen vem embutido no freeBSD. nem sempre está no pacote e2fsprogs.
Boa pessoa
1
@ Rob: Para responder à sua pergunta original, é para etiquetas de unidades .
Dennis Williamson
2
Percebo que o uuidgen no Mac emite em letras maiúsculas enquanto no Ubuntu (uuidgen do util-linux 2.20.1) em todas as letras minúsculas. Por que a diferença? Também o Ubuntu listou de onde a ferramenta veio, mas no Mac, não há informações de versão nem de qual pacote veio.
David
1
@ David: Eu acredito que faz parte do sistema operacional base no OS X. Eu não tenho idéia por que um é maiúsculo e o outro é mais baixo. Realmente não importa, uma vez que representa caracteres hexadecimais válidos ( echo -e 'f\nF' | grep '[[:xdigit:]]'gera as duas linhas). Se isso importa para você e você tem Bash 4, você pode fazer isso para torná-lo minúsculas: uuid=$(uuidgen); uuid=${uuid,,}ou isso para torná-lo maiúsculas: uuid=$(uuidgen); uuid=${uuid^^}ou algo nesse sentido para fazer um tolower()teste de estilo:if [[ ${uuid1,,} == ${uuid2,,} ]]
Dennis Williamson
168

Para adicionar variedade sem adicionar dependências externas, no Linux, você pode:

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

Para propagar más práticas, no FreeBSD , na camada de compatibilidade do linux (linuxulator?),

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

Referências:

Samveen
fonte
19
Isso é incrível.
Tom O'Connor
3
Isso deve ser evitado, pois é altamente não-portáteis (embora fontes do FreeBSD / compat / linux / proc / sys / kernel / random / uuid para aplicações mal escritas)
Boa Pessoa
1
Ele se encaixa perfeitamente para o uso dentro da imagem initrd
Maximilian
2
Essa deve ser a melhor resposta!
21816 dguerri
6
Essa é uma resposta melhor para configurações realmente mínimas, como um contêiner do Docker.
12136 jacderida
34

Apenas por uma questão de completude ... Há também um gerador UUID instalado com o dbuspacote no Debian. Eu senti falta de olhar ao redor mais cedo. Provavelmente é o mesmo algoritmo que o pacote e2fsprogs, mas não adiciona os traços, portanto pode ser um pouco mais limpo para você:

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

$ dbus-uuidgen
d17b671f98fced5649a856a54b51c9e6

O Grawity adiciona uma dica de segurança: "Os UUIDs do DBus não estão relacionados ou são compatíveis com o RFC 4122. Além disso, o dbus-uuidgen sempre usa o registro de data e hora do Unix como os últimos 4 bytes. Portanto, eles podem ser inadequados para alguns usos." (Obrigado, Grawity, eu deveria ter descoberto isso na página de manual.)

charlatão quixote
fonte
7
Os UUIDs do DBus não estão relacionados ou são compatíveis com o RFC 4122. Além disso, dbus-uuidgensempre usa o registro de data e hora do Unix como os últimos 4 bytes. Portanto, eles podem ser inadequados para alguns usos.
quer
mesmas obras sobre Fedora-25, também ...
kmonsoor
20

Se você não deseja depender de outros executáveis ​​ou não pode usá-los, aqui está a versão pura do bash a partir daqui :

# 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
de jeito nenhum
fonte
A Tvariável pode ser eliminada e o for Tloop pode ser alterado para: case $N in 3 | 5 | 7 | 9) printf '-';; esac(dividido em linhas separadas, se preferir).
Dennis Williamson
1
Adicionei um comentário ao código no link do github, mostrando uma versão usada casepara eliminar as ifdeclarações e a fordeclaração interna . Isso torna o código muito mais organizado. Observe que ambos B%15devem ser B%16e B%255devem ser B%256.
Dennis Williamson
colocá-lo on-line em um URL para que as pessoas possam source <(curl url)
adquiri-
19

Eu achei esse script "one-liner" útil quando o uuidgen não está disponível. Isso também ignora qualquer necessidade de instalar módulos externos para Perl ou Python.

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

Testado no SnowLeopard, Red Hat Valhalla, Solaris 9 4/04 e mais recente com sucesso. Estou curioso para saber se isso é propenso à não-exclusividade, mas não tenho estado assim nos últimos dez anos. Claro, head -1pode ser substituído por head -_other-value_ | tail -1também.

Explicar,

/dev/randome /dev/urandomsão geradores aleatórios do kernel.

od (octal dump) possui um comutador de saída hexadecimal (-x) produzindo 16 bytes por linha.

head-n [| tail -1] (onde n> 0) extrai apenas uma linha da saída anterior.

awkdefine o OutputFieldSeparator como um hífen em qualquer lugar em que uma vírgula ocorra na instrução print. Ao especificar os campos 2 a 9 independentemente, controlamos os hífens e eliminamos o contador de índice / deslocamento com o qual 'od' prefixa cada linha de saída.

O resultado é um padrão de 8-4-4-4-12caracteres minúsculos a-f0-9.

993bb8d7-323d-b5ee-db78-f976a59d8284
dan
fonte
1
Brilhante! apenas uma única linha sem dependências, compatível com BSD / macOS ... ótimo
dinigo
Você não usar "tail -1". Se você executar apenas "od -x / dev / urandom" por si só, ele continuará indefinidamente, produzindo continuamente mais linhas de dados aleatórios. "tail -1" pode ficar parado para sempre esperando a "última" linha. Caso contrário, é uma boa solução.
UncaAlby
Observe que tail é apenas na "explicação" como um parâmetro opcional quando o número de linhas emitidas pela cabeça é maior que um. Lá para garantir o recebimento de uma única linha de 16 bytes por awk, e não faz parte do comando original. O tubo a partir do od já limpa a saída da tubulação até o final -1. Na minha experiência, o único tempo que a cauda espera para sempre é com um argumento -f. Peço desculpas se a explicação não foi clara, onde afirma que o uso da cauda -1 é necessário apenas quando a saída da cabeça produz mais de uma linha.
dan
2
Você não usar isso, ele viola completamente a especificação UUID. Somente o UUID da versão 4 pode ser aleatório assim.
Jlh
3
@jlh Eu não sei por que esta pergunta foi bloqueado, mas aqui está uma versão fixa que torna essa abordagem UUID-v4 compatível: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

Apenas para que o python não se sinta deixado de fora:

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

Para usá-lo no shell:

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

Veja o UUID da documentação do Python para obter os tipos de UUIDS que podem ser gerados.

Para gerar um arquivo systemd compatível com o ID da máquina em uma máquina que não seja systemd, você pode usar o python da seguinte maneira:

python -c 'import re; import uuid; print re.sub("-","",str(uuid.uuid4()))' \
 > /etc/machine-id
davey
fonte
o uuid é um built-in?
Alexander Mills
O python já funcionou? Eu recebo esse arquivo "<string>", linha 1 import uuid; print uuid.uuid1 () ^ SyntaxError: sintaxe inválida `
Alexander Mills
1
Use python3 -c "import uuid; print(uuid.uuid4())"for python3
abdusco 29/07
11

O Perl fornece uma biblioteca UUID baseada no e2fsprogspacote. No meu sistema Debian é o libuuid-perlpacote. Aqui está um exemplo de uma linha; veja man uuidpara mais:

$ 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

Isso seria trivial para adicionar a um shellscript com backticks ou $()notação:

#!/bin/bash
# ...do some stuff
$myvar = $(perl -e 'use UUID;  UUID::generate($uuid);  UUID::unparse($uuid, $string);  print "$string";')
# ...do some more stuff
charlatão quixote
fonte
+1 - Me ajude bastante!
Rafa.ferreira
1

Eu escrevi uma pequena função Bash usando Python para gerar um número arbitrário de UUIDs em massa:

# 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 você preferir letras minúsculas, altere:

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

Para:

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

Por favor, consulte a biblioteca OSSP UUID ( http://www.ossp.org/pkg/lib/uuid/ ) e considere a instalação. Alguns projetos oferecem isso como uma opção (por exemplo, PostgreSQL). Ele lida adequadamente com os UUIDs das versões 3 e 5 , que estavam além do que minha biblioteca instalada (por exemplo, e2fsprogs) poderia suportar. Felizmente, o openSUSE o possui em um dos principais repositórios. Fazer uma versão funcionar com Windows (por exemplo, Cygwin) ou MySQL tem sido um fracasso. Parece que é hora de mudar para Linux / PostgreSQL / Python (e eu amei a GUI do SQLyog para MySQL / MariaDB), pois eu realmente preciso de UUIDs v3 e v5.

user2351170
fonte
Concordo completamente! Para o meu caso de uso, era perfeito, pois também suporta espaçamento de nomes por meio do -v3 ns:URL custom-datamecanismo de propagação.
Roberto Andrade
1

Tenho certeza de que alguns chegarão aqui e estão apenas procurando uma maneira fácil de gerar um ID exclusivo para uso em seus scripts, e não precisa ser um verdadeiro UUID.

Nesse caso, você pode simplesmente fazer o seguinte, o que gerará um ID exclusivo até o segundo; portanto, se você executar isso várias vezes em um segundo, ainda obterá o mesmo resultado.

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

irá gerar IDs como o seguinte com base na hora atual do sistema:

U1454423662

NOTA: Se você estiver no Linux ou tiver o Coreutils instalado em um mac, poderá usar o seguinte para gerar um ID exclusivo para o nanossegundo:

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

ou se você preferir uma solução baseada em python até o nanossegundo, que deve funcionar em quase todos os lugares, execute:

MYUID=U$(python -c'import time; print repr(time.time())')
echo $MYUID
Brad Parks
fonte
1
No geral, é uma prática muito ruim. Os computadores modernos são perfeitamente capazes de executar muitas coisas em paralelo e concluir tarefas seriais rapidamente, mas esse ID será idêntico para todas as invocações dentro de um segundo do outro. Sem mencionar outros computadores executando esse script ao mesmo tempo. A melhor-mas-ainda-não-ótima opção seria mktemp -ucomo em MYID="$(mktemp -u)". Se você pode dar ao luxo de ter os arquivos temporários vazias, que ao redor até reiniciar, gota a -u:MYID="$(mktemp)"
Chris Harrington
Ei ... bons pontos sobre o único exclusivo para o segundo ponto ... vou acrescentar algumas notas acima ...
Parques Brad
1

Esse tópico, com seus variados exemplos, foi realmente útil para mim. Freqüentemente preciso de funções uuid de vários ambientes diferentes. E embora eu adore os exemplos puros do bash, às vezes é mais conveniente usar uma biblioteca de um idioma diferente.

Portanto, apenas por questões de detalhe, o ruby ​​(1.9.3+) possui o módulo SecureRandom interno que contém várias funções úteis de hash e identificação. No bash cli, você pode fazer isso.

ruby -r securerandom -e 'puts SecureRandom.uuid'
wbr
fonte
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
fonte
3
Um pouco mais de explicação ajudaria a sua resposta
Dave M
x = od -X -A n /dev/random | head -1 | cut -c3-38 fornece isso abaixo 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, de volta ao bash depois de muitos anos fora, isso está muito no limite do meu conhecimento atual. Espero dividi-lo um pouco ajuda. Cheers, andyfff
andyfff
-1

Se você estiver usando o Java 10.

$ jshell
jshell> import java.util.*
jshell> String id = UUID.randomUUID().toString();
amit
fonte
Java 10 não é bash.
precisa saber é
Acabei de dar um exemplo de quão rapidamente ele pode gerar um UUID no terminal sem executar um programa java. As pessoas deram exemplo de uso de dbus-uuidgen e uuidgen . O que há de errado em usar o jshell?
Amit
1
@ amit o ponto é que você precisa dar um exemplo de onde jshellpode ser usado no script bash , e não como um comando interativo . Isso é muito claro no post original.
Samveen 27/09/18
Se você deve fazer algo listar isso, você poderia fazer echo "System.out.println(java.util.UUID.randomUUID().toString())" | /Library/Java/JavaVirtualMachines/openjdk-11.0.1.jdk/Contents/Home/bin/jshell -s | grep -v ">" Mas é muito mais demorado do que uuidgen.
mlk 5/03