Bagaimana cara membuat UUID di bash?

185

Di Jawa dimungkinkan untuk membuat UUID acak :

UUID uuid = UUID.randomUUID();

Bagaimana melakukan ini di Bash?

raoulsson
sumber

Jawaban:

225

Lihat uuidgenprogram yang merupakan bagian dari paket e2fsprogs .

Menurut ini , libuuidsekarang bagian dari util-linux dan penyertaan dalam e2fsprogs sedang dihapus. Namun, pada sistem Ubuntu baru, uuidgensekarang ada dalam uuid-runtimepaket.

Untuk membuat uuid dan menyimpannya dalam variabel:

uuid=$(uuidgen)

Pada sistem Ubuntu saya, karakter alfa adalah output sebagai huruf kecil dan pada sistem OS X saya, mereka adalah output sebagai huruf besar (terima kasih kepada David untuk menunjukkan ini dalam komentar).

Untuk beralih ke semua huruf besar (setelah membuatnya seperti di atas):

uuid=${uuid^^}

Untuk beralih ke semua huruf kecil:

uuid=${uuid,,}

Jika, misalnya, Anda memiliki dua UUID dan ingin membandingkannya di Bash, mengabaikan kasingnya, Anda dapat melakukan tolower()perbandingan gaya seperti ini:

if [[ ${uuid1,,} == ${uuid2,,} ]]
Dennis Williamson
sumber
7
hai, tidak adil! e2fsprogs saya tidak datang dengan itu! saya ingin satu, di mana saya mendapatkannya? (perbarui: ahhh ... debian memasukkannya ke dalam uuid-runtimepaket tanpa alasan yang jelas ... +1 untuk Anda)
quack quixote
uuidgen dibuat bawaan di FreeBSD. itu tidak selalu dalam paket e2fsprogs.
Orang Baik
1
@Rob: Untuk menjawab pertanyaan awal Anda, ini untuk label drive .
Dennis Williamson
2
Saya melihat uuidgen di Mac mengeluarkan semua huruf besar sementara di Ubuntu (uuidgen dari util-linux 2.20.1) di semua huruf kecil. Kenapa bedanya? Ubuntu juga mencantumkan dari mana alat itu berasal tetapi di Mac, tidak ada info versi atau paket asalnya.
David
1
@ David: Saya percaya itu adalah bagian dari sistem operasi dasar pada OS X. Saya tidak tahu mengapa satu huruf besar dan yang lain lebih rendah. Tidak masalah karena keduanya mewakili karakter hex yang valid ( echo -e 'f\nF' | grep '[[:xdigit:]]'menampilkan kedua baris). Jika itu penting bagi Anda dan Anda memiliki Bash 4, Anda dapat melakukan ini untuk membuatnya menjadi huruf kecil: uuid=$(uuidgen); uuid=${uuid,,}atau ini untuk membuatnya menjadi huruf besar: uuid=$(uuidgen); uuid=${uuid^^}atau sesuatu di sepanjang garis ini untuk melakukan tolower()tes gaya:if [[ ${uuid1,,} == ${uuid2,,} ]]
Dennis Williamson
168

Untuk menambahkan variasi tanpa menambahkan dependensi eksternal, di Linux Anda dapat melakukannya:

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

Untuk menyebarkan praktik buruk, di FreeBSD , di bawah lapisan kompatibilitas linux (linuxulator?),

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

Referensi:

Samveen
sumber
19
Ini luar biasa.
Tom O'Connor
3
Ini harus dihindari karena sangat non-portabel (walaupun FreeBSD memasok / compat / linux / proc / sys / kernel / random / uuid untuk aplikasi yang ditulis dengan buruk)
Orang Baik
1
Ini sangat cocok untuk penggunaan di dalam gambar initrd
Maximilian
2
Ini harus menjadi jawaban terbaik!
dguerri
6
Ini adalah jawaban yang lebih baik untuk pengaturan yang sangat minim, seperti wadah Docker.
jacderida
34

Hanya demi kelengkapan ... Ada juga generator UUID yang diinstal dengan dbuspaket di Debian. Saya melewatkannya melihat-lihat sebelumnya. Ini mungkin algoritma yang sama dengan paket e2fsprogs, tetapi tidak menambahkan tanda hubung, jadi mungkin akan sedikit lebih bersih untuk Anda:

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

$ dbus-uuidgen
d17b671f98fced5649a856a54b51c9e6

Grawity menambahkan tip keamanan: "DBus UUID tidak terkait atau tidak kompatibel dengan RFC 4122. Selain itu, dbus-uuidgen selalu menggunakan cap waktu Unix sebagai 4 byte terakhir. Jadi, mereka mungkin tidak cocok untuk beberapa penggunaan." (Terima kasih, Grawity, aku seharusnya melihatnya di halaman manual.)

quack quixote
sumber
7
DBus UUID tidak terkait atau kompatibel dengan RFC 4122. Selain itu, dbus-uuidgenselalu menggunakan cap waktu Unix sebagai 4 byte terakhir. Jadi mereka mungkin tidak cocok untuk beberapa kegunaan.
grawity
karya yang sama pada Fedora-25, juga ...
kmonsoor
20

Jika Anda tidak ingin bergantung pada executable lain, atau Anda tidak dapat menggunakannya, berikut ini adalah versi bash murni dari sini :

# 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
tidak mungkin
sumber
The Tvariabel dapat dihilangkan dan for Tlingkaran dapat diubah ke: case $N in 3 | 5 | 7 | 9) printf '-';; esac(pecah pada baris yang berbeda jika pilihan).
Dennis Williamson
1
Saya menambahkan komentar ke kode di tautan github yang menunjukkan versi yang digunakan caseuntuk menghilangkan ifpernyataan serta forpernyataan dalam . Itu membuat kode lebih rapi. Perhatikan bahwa keduanya B%15harus B%16dan B%255seharusnya B%256.
Dennis Williamson
letakkan online di url sehingga orang dapat sumber dan mencobanya source <(curl url)atau apa pun
MrCholo
19

Saya telah menemukan bahwa skrip ini "satu garis" berguna di mana uuidgen tidak tersedia. Ini juga memotong setiap neccessity untuk menginstal modul eksternal untuk Perl atau Python.

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

Diuji pada SnowLeopard, Red Hat Valhalla, Solaris 9 4/04 dan yang lebih baru berhasil. Saya ingin tahu apakah ini cenderung non-keunikan, tapi saya belum pernah 'bit'ten dalam 10 tahun terakhir. Tentu saja head -1bisa diganti head -_other-value_ | tail -1juga.

Untuk menjelaskan,

/dev/randomdan /dev/urandommerupakan generator acak kernel.

od (octal dump) memiliki hex output switch (-x) yang menghasilkan 16 byte per baris.

head-n [| tail -1] (di mana n> 0) mengekstrak hanya satu baris dari output sebelumnya.

awkmengatur OutputFieldSeparator menjadi tanda hubung di mana-mana koma muncul dalam pernyataan cetak. Dengan menetapkan bidang 2-9 secara independen, kami mengontrol tanda hubung dan menanggalkan indeks / penghitung offset yang diawali dengan 'od' setiap baris keluaran.

Hasilnya adalah pola 8-4-4-4-12karakter huruf kecil a-f0-9.

993bb8d7-323d-b5ee-db78-f976a59d8284
dan
sumber
1
Cemerlang! hanya satu baris tanpa ketergantungan, BSD / macOS kompatibel ... hebat
dinigo
Apakah TIDAK menggunakan "ekor -1". Jika Anda menjalankan sendiri "od -x / dev / urandom" dengan sendirinya, itu berjalan tanpa batas waktu, terus menerus menghasilkan lebih banyak baris data acak. "tail -1" mungkin hanya duduk di sana selamanya menunggu baris "terakhir". Kalau tidak, itu solusi yang baik.
UncaAlby
Harap dicatat, tail hanya ada di "penjelasan" sebagai parameter opsional ketika jumlah garis yang dihasilkan oleh head lebih besar dari satu. Di sana untuk memastikan menerima satu baris 16 byte oleh awk, dan bukan bagian dari perintah asli. Pipa untuk menuju dari od sudah membersihkan output untuk pemipaan ke tail -1. Dalam pengalaman saya, satu-satunya waktu menunggu selamanya adalah dengan argumen -f. Saya minta maaf jika penjelasannya tidak jelas di mana ia menyatakan penggunaan ekor -1 hanya diperlukan ketika output dari head menghasilkan lebih dari satu baris.
dan
2
Jangan tidak menggunakan ini, itu benar-benar melanggar spesifikasi UUID. Hanya UUID versi 4 diizinkan secara acak seperti ini.
jlh
3
@ jlh Saya tidak yakin mengapa pertanyaan ini dikunci, tetapi inilah versi tetap yang membuat pendekatan ini sesuai dengan 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

Hanya saja python tidak merasa ditinggalkan:

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

Untuk menggunakannya di shell:

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

Lihat UUID Dokumentasi Python untuk jenis-jenis UUIDS yang dapat dihasilkan.

Untuk menghasilkan file yang kompatibel dengan systemd-id mesin pada mesin non-systemd, Anda bisa menggunakan python untuk melakukannya dengan cara ini:

python -c 'import re; import uuid; print re.sub("-","",str(uuid.uuid4()))' \
 > /etc/machine-id
davey
sumber
apakah uuid adalah built-in?
Alexander Mills
Pernahkah python bekerja? Saya mendapatkan `File" <string> "ini, baris 1 impor uuid; print uuid.uuid1 () ^ SyntaxError: sintaks tidak valid `
Alexander Mills
1
Gunakan python3 -c "import uuid; print(uuid.uuid4())"untuk python3
abdusco
11

Perl menyediakan pustaka UUID berdasarkan e2fsprogspaket. Di sistem Debian saya itu libuuid-perlpaket. Berikut ini contoh one-liner; lihat man uuidlebih lanjut:

$ 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

Ini sepele untuk ditambahkan ke shellscript dengan backticks atau $()notasi:

#!/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
sumber
+1 - Banyak membantu saya!
rafa.ferreira
1

Saya menulis sedikit fungsi Bash menggunakan Python untuk menghasilkan sejumlah UUID dalam jumlah besar:

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

Jika Anda lebih suka huruf kecil, ubah:

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

Untuk:

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

Silakan lihat pustaka UUS OSSP ( http://www.ossp.org/pkg/lib/uuid/ ), dan pertimbangkan untuk menginstalnya. Beberapa proyek menawarkannya sebagai opsi (misalnya PostgreSQL). Ia menangani dengan benar UUID versi 3 dan versi 5 , yang melampaui apa yang bisa ditangani oleh perpustakaan saya yang terinstal (misalnya e2fsprogs). Untungnya, openSUSE memilikinya di salah satu repo utama. Mendapatkan versi untuk bekerja dengan Windows (misalnya Cygwin) atau MySQL telah gagal. Sepertinya sudah waktunya untuk beralih ke Linux / PostgreSQL / Python (dan saya sangat menyukai GUI SQLyog ke MySQL / MariaDB) karena saya benar-benar membutuhkan UUID v3 dan v5.

pengguna2351170
sumber
Setuju sepenuhnya! Untuk kasus penggunaan saya, itu sempurna karena juga mendukung penamaan nama melalui -v3 ns:URL custom-datamekanisme penyemaian.
Roberto Andrade
1

Saya yakin beberapa akan tiba di sini, dan hanya mencari cara mudah untuk menghasilkan ID unik untuk digunakan dalam skrip mereka, dan itu tidak perlu menjadi UUID sejati.

Jika demikian, Anda bisa melakukan hal berikut, yang akan menghasilkan id yang unik hingga yang kedua - jadi jika Anda menjalankan ini beberapa kali dalam satu detik, Anda masih akan mendapatkan hasil yang sama.

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

akan menghasilkan id seperti berikut berdasarkan waktu sistem saat ini:

U1454423662

CATATAN: Jika Anda menggunakan Linux, atau menginstal Coreutils di mac, maka Anda dapat menggunakan yang berikut ini untuk menghasilkan id unik ke nanosecond:

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

atau jika Anda lebih suka solusi berbasis python ke nanosecond, yang seharusnya bekerja hampir di mana saja, jalankan:

MYUID=U$(python -c'import time; print repr(time.time())')
echo $MYUID
Taman Brad
sumber
1
Ini secara keseluruhan merupakan praktik yang sangat buruk. Komputer modern sangat mampu menjalankan banyak hal secara paralel dan menyelesaikan tugas serial dengan cepat, tetapi ID ini akan identik untuk setiap doa yang berada dalam satu detik dari yang lain. Belum lagi komputer lain yang menjalankan skrip ini secara bersamaan. Opsi yang lebih baik-tetapi-masih-tidak-bagus adalah mktemp -useperti pada MYID="$(mktemp -u)". Jika Anda dapat memiliki file temp kosong yang diletakkan di sekitar sampai reboot, jatuhkan -u:MYID="$(mktemp)"
Chris Harrington
Hei ... poin bagus pada satu-satunya yang unik ke poin kedua ... Saya akan menambahkan beberapa catatan di atas ...
Brad Parks
1

Utas ini, dengan beragam contoh, benar-benar bermanfaat bagi saya. Saya sering membutuhkan fungsi uuid dari sejumlah lingkungan yang berbeda. Dan meskipun saya menyukai contoh-contoh bash murni, terkadang lebih nyaman menggunakan perpustakaan dari bahasa yang berbeda.

Jadi hanya untuk ketelitian, ruby ​​(1.9.3+) memiliki modul SecureRandom bawaan yang berisi sejumlah fungsi hash dan id yang berguna. Dari bash cli, Anda bisa melakukan ini.

ruby -r securerandom -e 'puts SecureRandom.uuid'
wbr
sumber
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
sumber
3
Penjelasan lebih banyak akan membantu jawaban Anda
Dave M
x = od -X -A n /dev/random | head -1 | cut -c3-38 memberi Anda ini di bawah 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, kembali melakukan bash setelah bertahun-tahun pergi, ini sangat di ujung pengetahuan saya saat ini. Semoga memecahnya sedikit membantu. ceria, andyfff
andyfff
-1

Jika Anda menggunakan Java 10.

$ jshell
jshell> import java.util.*
jshell> String id = UUID.randomUUID().toString();
ya
sumber
Java 10 bukan bash.
kasperd
Saya hanya memberi contoh seberapa cepat dia bisa menghasilkan UUID di terminal tanpa menjalankan program java. Orang memberi contoh penggunaan dbus-uuidgen dan uuidgen . Apa yang salah dengan menggunakan jshell?
amit
1
@it intinya adalah bahwa Anda perlu memberikan contoh di mana jshelldapat digunakan dalam bash scripting , dan bukan sebagai perintah interaktif . Itu sangat jelas dalam posting asli.
Samveen
Jika Anda harus melakukan sesuatu daftar ini, Anda bisa melakukannya echo "System.out.println(java.util.UUID.randomUUID().toString())" | /Library/Java/JavaVirtualMachines/openjdk-11.0.1.jdk/Contents/Home/bin/jshell -s | grep -v ">" Tapi itu jauh lebih panjang daripada uuidgen.
mlk