Làm thế nào để tạo UUID trong bash?


185

Trong Java, có thể tạo UUID ngẫu nhiên :

UUID uuid = UUID.randomUUID();

Làm thế nào để làm điều này trong Bash?

Câu trả lời:


225

Xem uuidgenchương trình là một phần của gói e2fspross .

Theo đó , libuuidbây giờ là một phần của linux-linux và việc đưa vào e2fspross đang được loại bỏ. Tuy nhiên, trên các hệ thống Ubuntu mới, uuidgenhiện đã có trong uuid-runtimegói.

Để tạo một uuid và lưu nó trong một biến:

uuid=$(uuidgen)

Trên hệ thống Ubuntu của tôi, các ký tự alpha được xuất thành chữ thường và trên hệ thống OS X của tôi, chúng là đầu ra dưới dạng chữ hoa (cảm ơn David đã chỉ ra điều này trong một bình luận).

Để chuyển sang tất cả chữ hoa (sau khi tạo như trên):

uuid=${uuid^^}

Để chuyển sang tất cả các chữ thường:

uuid=${uuid,,}

Ví dụ, nếu bạn có hai UUID và bạn muốn so sánh chúng trong Bash, bỏ qua trường hợp của chúng, bạn có thể thực hiện tolower()so sánh kiểu như thế này:

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

7
này, không công bằng! e2fspross của tôi đã không đi kèm với điều đó! tôi muốn một cái, tôi lấy nó ở đâu? (cập nhật: ahhh ... debian nhét nó vào uuid-runtimegói mà không có lý do rõ ràng ... +1 cho bạn)
quackote quixote

uuidgen được tích hợp sẵn trên freeBSD. không phải lúc nào cũng có trong gói e2fspross.
Người tốt

1
@Rob: Để trả lời câu hỏi ban đầu của bạn, đó là nhãn ổ đĩa .
Dennis Williamson

2
Tôi nhận thấy uuidgen trên Mac phát ra ở tất cả chữ hoa trong khi trên Ubuntu (uuidgen từ produc-linux 2.20.1) ở tất cả chữ thường. Tại sao lại có sự khác biệt? Ngoài ra Ubuntu được liệt kê nơi công cụ đến từ nhưng trên Mac, không có thông tin phiên bản cũng như gói đến từ đâu.
David

1
@David: Tôi tin rằng đó là một phần của hệ điều hành cơ bản trên OS X. Tôi không biết tại sao một cái lại là chữ hoa và cái kia thì thấp hơn. Nó không thực sự quan trọng vì một trong hai đại diện cho các ký tự hex hợp lệ ( echo -e 'f\nF' | grep '[[:xdigit:]]'xuất cả hai dòng). Nếu nó có vấn đề với bạn và bạn có Bash 4, bạn có thể làm điều này để viết chữ thường: uuid=$(uuidgen); uuid=${uuid,,}hoặc điều này để viết hoa: uuid=$(uuidgen); uuid=${uuid^^}hoặc một cái gì đó dọc theo những dòng này để thực hiện tolower()bài kiểm tra phong cách:if [[ ${uuid1,,} == ${uuid2,,} ]]
Dennis Williamson

168

Để thêm đa dạng mà không cần thêm phụ thuộc bên ngoài, trên Linux, bạn có thể làm:

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

Để truyền bá các thực tiễn xấu, trên FreeBSD , dưới lớp tương thích linux (linuxulator?),

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

Người giới thiệu:


19
Điều này thật tuyệt.
Tom O'Connor

3
Điều này nên tránh vì nó không có tính di động cao (mặc dù FreeBSD cung cấp / compat / linux / Proc / sys / kernel / Random / uuid cho các ứng dụng được viết kém)
Người tốt

1
Nó phù hợp hoàn hảo để sử dụng bên trong hình ảnh initrd
Maximilian

2
Đây nên là câu trả lời tốt nhất!
dguerri

6
Đây là một câu trả lời tốt hơn cho các thiết lập thực sự tối thiểu, như một container Docker.
jacderida

34

Chỉ vì mục đích hoàn chỉnh ... Ngoài ra còn có một trình tạo UUID được cài đặt cùng với dbusgói trên Debian. Tôi nhớ nó nhìn xung quanh sớm hơn. Đây có thể là thuật toán tương tự như gói e2fspross, nhưng nó không thêm dấu gạch ngang, vì vậy nó có thể sạch hơn một chút cho bạn:

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

$ dbus-uuidgen
d17b671f98fced5649a856a54b51c9e6

Grawity bổ sung một mẹo an toàn: "DBus UUID không liên quan hoặc tương thích với RFC 4122. Bên cạnh đó, dbus-uuidgen luôn sử dụng dấu thời gian Unix làm 4 byte cuối cùng. Vì vậy, chúng có thể không phù hợp với một số mục đích sử dụng." (Cảm ơn, Grawity, tôi đã phát hiện ra điều đó trong trang chủ.)


7
Các UUID DBus không liên quan đến hoặc tương thích với RFC 4122. Bên cạnh đó, dbus-uuidgenluôn sử dụng dấu thời gian Unix làm 4 byte cuối cùng. Vì vậy, chúng có thể không phù hợp cho một số sử dụng.
grawity

cũng hoạt động trên Fedora-25, ...
kmonsoor

20

Nếu bạn không muốn phụ thuộc vào các tệp thực thi khác hoặc bạn không thể sử dụng chúng, đây là phiên bản bash thuần túy từ đây :

# 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

Các Tbiến thể được loại bỏ và các for Tvòng lặp có thể được thay đổi để: case $N in 3 | 5 | 7 | 9) printf '-';; esac(nổ ra trên dòng riêng biệt nếu ưa thích).
Dennis Williamson

1
Tôi đã thêm một nhận xét vào mã tại liên kết github hiển thị một phiên bản sử dụng caseđể loại bỏ các ifcâu lệnh cũng như forcâu lệnh bên trong . Nó làm cho mã gọn gàng hơn nhiều. Lưu ý rằng cả hai B%15nên B%16B%255nên B%256.
Dennis Williamson

đặt nó trực tuyến tại một url để mọi người có thể tìm nguồn và thử nó source <(curl url)hoặc bất cứ điều gì
MrCholo

19

Tôi đã tìm thấy tập lệnh này "one-liner" hữu ích khi không có sẵn uuidgen. Điều này cũng bỏ qua mọi sự cần thiết để cài đặt các mô-đun bên ngoài cho Perl hoặc Python.

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

Đã thử nghiệm trên SnowLeopard, Red Hat Valhalla, Solaris 9 4/04 và mới hơn thành công. Tôi tò mò liệu điều này có xu hướng không độc đáo, nhưng tôi đã không 'bit'ten trong 10 năm qua. Tất nhiên, head -1có thể được thay thế bằng head -_other-value_ | tail -1quá.

Giải thích,

/dev/random/dev/urandomlà các bộ tạo ngẫu nhiên kernel.

od (kết xuất bát phân) có một công tắc đầu ra hex (-x) tạo ra 16 byte trên mỗi dòng.

head-n [| đuôi -1] (trong đó n> 0) chỉ trích xuất một dòng của đầu ra trước đó.

awkđặt OutputFieldSpayator thành dấu gạch nối ở mọi nơi xảy ra dấu phẩy trong câu lệnh in. Bằng cách chỉ định các trường 2-9 một cách độc lập, chúng tôi kiểm soát các dấu gạch nối và loại bỏ bộ đếm chỉ số / bộ bù mà tiền tố 'od' đặt trước mỗi dòng đầu ra.

Kết quả là một mô hình các 8-4-4-4-12ký tự chữ thường a-f0-9.

993bb8d7-323d-b5ee-db78-f976a59d8284

1
Xuất sắc! chỉ là một dòng duy nhất không có phụ thuộc, tương thích BSD / macOS ... tuyệt vời
dinigo

Đừng KHÔNG sử dụng "đuôi -1". Nếu bạn chỉ chạy "od -x / dev / urandom", nó sẽ tiếp tục vô tận, liên tục tạo ra nhiều dòng dữ liệu ngẫu nhiên. "Đuôi -1" có thể chỉ ngồi đó chờ đợi dòng "cuối cùng". Mặt khác, nó là một giải pháp tốt.
UncaAlby

Xin lưu ý, đuôi chỉ nằm trong "giải thích" dưới dạng tham số tùy chọn khi số lượng dòng đầu ra của đầu lớn hơn một. Ở đó để đảm bảo nhận được một dòng 16 byte bằng awk và không phải là một phần của lệnh gốc. Các ống dẫn đến đầu từ od đã vệ sinh đầu ra cho đường ống đến đuôi -1. Theo kinh nghiệm của tôi, cái đuôi thời gian duy nhất chờ đợi mãi mãi là với một đối số -f. Tôi xin lỗi nếu lời giải thích không rõ ràng nơi nó nói rằng việc sử dụng đuôi -1 chỉ cần thiết khi đầu ra của đầu tạo ra nhiều hơn một dòng.
dan

2
Đừng không sử dụng này, nó hoàn toàn vi phạm các đặc điểm kỹ thuật UUID. Chỉ UUID phiên bản 4 mới được phép ngẫu nhiên như thế này.
jlh

3
@jlh Tôi không chắc tại sao câu hỏi này bị khóa, nhưng đây là phiên bản cố định làm cho cách tiếp cận này tuân thủ 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

Chỉ để con trăn không cảm thấy bị bỏ rơi:

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

Để sử dụng nó trong vỏ:

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

Xem UUID Tài liệu Python để biết các loại UUIDS có thể được tạo.

Để tạo tệp tương thích id máy systemd trên máy không phải systemd, bạn có thể sử dụng python để thực hiện theo cách này:

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

uuid có tích hợp không?
Alexander Mills

Con trăn đã từng làm việc chưa? Tôi nhận được `File" <string> "này, dòng 1 nhập uuid; print uuid.uuid1 () ^ Cú pháp: cú pháp không hợp lệ `
Alexander Mills

1
Sử dụng python3 -c "import uuid; print(uuid.uuid4())"cho python3
abdusco

11

Perl cung cấp một thư viện UUID dựa trên e2fsprogsgói. Trên hệ thống Debian của tôi, đó là libuuid-perlgói. Đây là một ví dụ một lót; xem man uuidthêm:

$ 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

Điều này sẽ không quan trọng để thêm vào shellscript với backticks hoặc $()ký hiệu:

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

+1 - Giúp tôi rất nhiều!
rafa.ferreira


1

Tôi đã viết một hàm Bash nhỏ bằng Python để tạo số lượng lớn UUID tùy ý:

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

Nếu bạn thích chữ thường, hãy thay đổi:

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

Đến:

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

1

Vui lòng xem thư viện OSSP UUID ( http://www.ossp.org/pkg/lib/uuid/ ) và xem xét việc cài đặt nó. Một số dự án cung cấp nó dưới dạng tùy chọn (ví dụ PostgreSQL). Nó xử lý đúng các UUID phiên bản 3 và 5 phiên bản , vượt xa những gì mà thư viện đã cài đặt (ví dụ e2fspross) của tôi có thể xử lý. May mắn thay, openSUSE có nó trong một trong những repos chính. Bắt phiên bản hoạt động với Windows (ví dụ Cygwin) hoặc MySQL là một lỗi. Có vẻ như đã đến lúc chuyển sang Linux / PostgreSQL / Python (và tôi rất thích GUI SQLyog sang MySQL / MariaDB) vì tôi thực sự cần UUID v3 và v5.


Hoan toan Đông y! Đối với trường hợp sử dụng của tôi, nó rất hoàn hảo vì nó cũng hỗ trợ không gian tên thông qua -v3 ns:URL custom-datacơ chế gieo hạt.
Roberto Andrade

1

Tôi chắc chắn một số người sẽ đến đây và đang tìm kiếm một cách dễ dàng để tạo một ID duy nhất để sử dụng trong các tập lệnh của họ và nó không cần phải là một UUID thực sự.

Nếu vậy, bạn chỉ có thể thực hiện các thao tác sau, sẽ tạo một id duy nhất xuống thứ hai - vì vậy nếu bạn chạy nó nhiều lần trong vòng một giây, bạn vẫn sẽ nhận được kết quả tương tự.

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

sẽ tạo id như sau dựa trên thời gian hệ thống hiện tại:

U1454423662

LƯU Ý: Nếu bạn đang dùng Linux hoặc cài đặt Coreutils trên máy mac, thì bạn có thể sử dụng cách sau để tạo id duy nhất cho nano giây:

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

hoặc nếu bạn thích một giải pháp dựa trên python xuống đến nano giây, hoạt động gần như ở mọi nơi, hãy chạy:

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

1
Đây là một thực tế rất xấu. Các máy tính hiện đại hoàn toàn có khả năng chạy song song nhiều thứ và hoàn thành các tác vụ nối tiếp một cách nhanh chóng, nhưng ID này sẽ giống hệt nhau cho bất kỳ yêu cầu nào trong vòng một giây. Không đề cập đến bất kỳ máy tính khác chạy tập lệnh này cùng một lúc. Một lựa chọn tốt hơn nhưng vẫn không tuyệt vời sẽ mktemp -unhư trong MYID="$(mktemp -u)". Nếu bạn có đủ khả năng để có các tệp tạm thời trống nằm xung quanh cho đến khi khởi động lại, hãy thả -u:MYID="$(mktemp)"
Chris Harrington

Này ... những điểm tốt duy nhất ở điểm thứ hai ... Tôi sẽ thêm một số ghi chú ở trên ...
Brad

1

Chủ đề này, với các ví dụ đa dạng của nó, thực sự hữu ích với tôi. Tôi thường xuyên cần các chức năng uuid từ một số môi trường khác nhau. Và trong khi tôi yêu các ví dụ bash thuần túy, đôi khi sử dụng thư viện từ một ngôn ngữ khác sẽ thuận tiện hơn.

Vì vậy, chỉ cần kỹ lưỡng, ruby ​​(1.9.3+) có mô-đun SecureRandom tích hợp có chứa một số hàm băm và id hữu ích. Từ bash cli, bạn có thể làm điều này.

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
Một chút giải thích sẽ giúp câu trả lời của bạn
Dave M

x = od -X -A n /dev/random | head -1 | cut -c3-38 cung cấp cho bạn dưới đây 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-1f7d0bef-8a07-25fbd26183a3
andyfff

Dave M, trở lại làm bash sau nhiều năm xa cách, điều này rất nhiều ở rìa của kiến ​​thức hiện tại của tôi. Hy vọng phá vỡ nó một chút giúp đỡ. chúc mừng, andyfff
andyfff

-1

Nếu bạn đang sử dụng Java 10.

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

Java 10 không phải là bash.
kasperd

Tôi vừa đưa ra một ví dụ về việc anh ta có thể tạo UUID trên thiết bị đầu cuối nhanh như thế nào mà không cần chạy chương trình java. Mọi người đã đưa ra ví dụ về việc sử dụng dbus-uuidgenuuidgen . Có gì sai khi sử dụng jshell?
amit

1
@amit điểm là bạn cần phải đưa ra một ví dụ trong đó jshellcó thể được sử dụng trong bash kịch bản , và không phải là một lệnh tương tác . Điều đó rất rõ ràng trong bài viết gốc.
Samveen

Nếu bạn phải làm một cái gì đó liệt kê điều này, bạn có thể làm echo "System.out.println(java.util.UUID.randomUUID().toString())" | /Library/Java/JavaVirtualMachines/openjdk-11.0.1.jdk/Contents/Home/bin/jshell -s | grep -v ">" Nhưng nó dài hơn rất nhiều uuidgen.
mlk
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.