How to create a UUID in bash?

260,719

Solution 1

See the uuidgen program which is part of the e2fsprogs package.

According to this, libuuid is now part of util-linux and the inclusion in e2fsprogs is being phased out. However, on new Ubuntu systems, uuidgen is now in the uuid-runtime package.

To create a uuid and save it in a variable:

uuid=$(uuidgen)

On my Ubuntu system, the alpha characters are output as lower case and on my OS X system, they are output as upper case (thanks to David for pointing this out in a comment).

To switch to all upper case (after generating it as above):

uuid=${uuid^^}

To switch to all lower case:

uuid=${uuid,,}

If, for example, you have two UUIDs and you want to compare them in Bash, ignoring their case, you can do a tolower() style comparison like this:

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

Solution 2

To add variety without adding external dependencies, on Linux you can do:

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

To propagate bad practices, on FreeBSD, under the linux compatibility layer (linuxulator?),

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

References:

Solution 3

Just for the sake of completeness... There's also a UUID generator installed with the dbus package on Debian. I missed it looking around earlier. It's probably the same algorithm as the e2fsprogs package, but it doesn't add the dashes, so it might be a little cleaner for you:

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

$ dbus-uuidgen
d17b671f98fced5649a856a54b51c9e6

Grawity adds a safety tip: "DBus UUIDs are not related to or compatible with RFC 4122. Besides, dbus-uuidgen always uses the Unix timestamp as the last 4 bytes. So they might be unsuitable for some uses." (Thanks, Grawity, I should've spotted that in the manpage.)

Solution 4

If you do not want to depend on other executables, or you cannot use them, here is the pure bash version from here:

# 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

Solution 5

I have found this script "one-liner" useful where uuidgen is not available. This also bypasses any neccessity to install external modules for Perl or Python.

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

Tested on SnowLeopard, Red Hat Valhalla, Solaris 9 4/04 and newer successfully. I am curious if this is prone to non-uniqueness, but I have not been 'bit'ten in the last 10 years. Of course, head -1 could be replaced with head -_other-value_ | tail -1 too.

To explain,

/dev/random and /dev/urandom are kernel random generators.

od (octal dump) has a hex output switch (-x) producing 16 bytes per line.

head -n [| tail -1] (where n>0) extracts just one line of the previous output.

awk sets the OutputFieldSeparator to be a hyphen everywhere a comma occurs in the print statement. By specifying fields 2-9 independently, we control the hyphens and strip off the index/offset counter that 'od' prefixes each line of output with.

The result is a pattern of 8-4-4-4-12 lower case characters a-f0-9.

993bb8d7-323d-b5ee-db78-f976a59d8284
Share:
260,719

Related videos on Youtube

raoulsson
Author by

raoulsson

CTO at Contovista AG Before: CEO at Zorp Technologies Inc., San Francisco, ...until Google Lens came out... Experienced software engineer and teamlead looking to build/enable useful, delightful, and meaningful products. Passionate, hard-worker interested in contributing to team-oriented, strong engineering cultures. Proven track record of hiring and running successful teams.

Updated on September 17, 2022

Comments

  • raoulsson
    raoulsson over 1 year

    In Java it is possible to create a random UUID:

    UUID uuid = UUID.randomUUID();
    

    How to do this in Bash?

  • quack quixote
    quack quixote over 14 years
    hey, no fair! my e2fsprogs didn't come with that! i want one, where do i get it? (update: ahhh... debian sticks it in the uuid-runtime package for no apparent reason... +1 to you)
  • user1686
    user1686 over 14 years
    DBus UUIDs are not related to or compatible with RFC 4122. Besides, dbus-uuidgen always uses the Unix timestamp as the last 4 bytes. So they might be unsuitable for some uses.
  • rafa.ferreira
    rafa.ferreira about 13 years
    +1 - Help me a lot!
  • Tom O'Connor
    Tom O'Connor over 10 years
    This is awesome.
  • Good Person
    Good Person almost 10 years
    This should be avoided as it is highly non-portable (although FreeBSD supplies /compat/linux/proc/sys/kernel/random/uuid for poorly written applications)
  • Dennis Williamson
    Dennis Williamson almost 10 years
    The T variable can be eliminated and the for T loop can be changed to: case $N in 3 | 5 | 7 | 9) printf '-';; esac (broken out on separate lines if preferred).
  • Dennis Williamson
    Dennis Williamson almost 10 years
    I added a comment to the code at the github link showing a version using case to eliminate the if statements as well as the inner for statement. It makes the code much neater. Note that both B%15 should be B%16 and B%255 should be B%256.
  • Rob
    Rob almost 10 years
    EDIT: Just read the last line. I'm a dork. Please carry on..... Be interested to hear why this is bundled in e2fsprogs, as this doesn't really seem that much like a filesystem-specific tool to me.
  • Dennis Williamson
    Dennis Williamson almost 10 years
    @Rob: To answer your original question, it's for drive labels.
  • Maximilian
    Maximilian almost 9 years
    It fits perfectly for usage inside of initrd image
  • Roberto Andrade
    Roberto Andrade over 8 years
    Agree completely! For my use case it was perfect as it also supports namespacing via the -v3 ns:URL custom-data seeding mechanism.
  • David
    David over 8 years
    The FreeBSD method doesn't appear to be on Mac OS X (nor the Linux method). At least uuidgen appears to be preinstalled on the Mac (or was installed with something else I installed).
  • David
    David over 8 years
    I notice uuidgen on Mac emits in all uppercase while on Ubuntu (uuidgen from util-linux 2.20.1) in all lowercase. Why the difference? Also Ubuntu listed where the tool came from but on Mac, there's no version info nor which package it came from.
  • Dennis Williamson
    Dennis Williamson over 8 years
    @David: I believe it's part of the base operating system on OS X. I have no idea why one is upper case and the other is lower. It doesn't really matter since either represents valid hex characters (echo -e 'f\nF' | grep '[[:xdigit:]]' outputs both lines). If it does matter for you and you have Bash 4, you can do this to make it lower case: uuid=$(uuidgen); uuid=${uuid,,} or this to make it upper case: uuid=$(uuidgen); uuid=${uuid^^} or something along these lines to do a tolower() style test: if [[ ${uuid1,,} == ${uuid2,,} ]]
  • Samveen
    Samveen over 8 years
    @David you are absolutely right. The FreeBSD method is for FreeBSD, and the Linux method is for Linux, as mentioned in the answer. Any bash script that need to run on all 3 systems (FreeBSD, Linux, MacOS) will need to check against uname -s and use the appropriate method.
  • dguerri
    dguerri about 8 years
    This should be the best answer!
  • jacderida
    jacderida almost 8 years
    This is a better answer for really minimal setups, like a Docker container.
  • Chris Harrington
    Chris Harrington over 7 years
    This is overall a very bad practice. Modern computers are perfectly capable of running many things in parallel and completing serial tasks quickly, but this ID will be identical for any invocations that are within one second of another. Not to mention any other computers running this script at the same time. A better-but-still-not-great option would be mktemp -u as in MYID="$(mktemp -u)". If you can afford to have empty temp files laying around until reboot, drop the -u: MYID="$(mktemp)"
  • Brad Parks
    Brad Parks over 7 years
    Hey... good points on the only unique to the second point... I'll add some notes above...
  • dinigo
    dinigo over 7 years
    Brilliant! just a single line with no dependencies, BSD/macOS compatible... great
  • kmonsoor
    kmonsoor over 6 years
    same works on Fedora-25, too ...
  • UncaAlby
    UncaAlby over 6 years
    Do NOT use "tail -1". If you run just "od -x /dev/urandom" by itself, it goes on indefinitely, continuously producing more lines of random data. "tail -1" may just sit there forever waiting for the "last" line. Otherwise, it's a good solution.
  • dan
    dan over 6 years
    Please note, tail is only in the "explanation" as an optional parameter when the number of lines output by head is greater than one. There to ensure receiving a single line of 16 bytes by awk, and is not part of the original command. The pipe to head from od already sanitizes the output for piping to tail -1. In my experience, the only time tail waits forever is with a -f argument. I apologize if the explanation was not clear where it states the use of tail -1 is only necessary when the output of head produces more than one line.
  • jlh
    jlh almost 6 years
    Do not use this, it completely violates the UUID specification. Only version 4 UUID are allowed to be random like this.
  • andyfff
    andyfff almost 6 years
    x=od -X -A n /dev/random | head -1 | cut -c3-38 gives you this below 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 almost 6 years
    Dave M, back doing bash after many years away, this is very much at the edge of my current knowldge. Hope breaking it down a bit helps. cheers, andyfff
  • kasperd
    kasperd over 5 years
    Java 10 is not bash.
  • amit
    amit over 5 years
    I just gave an example on how quickly he can generate a UUID on terminal without running a java program. People gave example of using dbus-uuidgen and uuidgen. Whats wrong with using jshell?
  • Samveen
    Samveen over 5 years
    @amit the point is that you need to give an example where jshell can be used in bash scripting, and not as an interactive command. That is very clear in the original post.
  • Stuart P. Bentley
    Stuart P. Bentley over 5 years
    @jlh I'm not sure why this question was locked, but here's a fixed version that makes this approach UUID-v4 compliant: 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}'
  • mlk
    mlk about 5 years
    If you must do something list this, you could do echo "System.out.println(java.util.UUID.randomUUID().toString())" | /Library/Java/JavaVirtualMachines/openjdk-11.0.1.jdk/Content‌​s/Home/bin/jshell -s | grep -v ">" But it is a lot more long winded than uuidgen.
  • Alexander Mills
    Alexander Mills almost 5 years
    Ummm I just want to know how to install one of these on macos or linux...pls
  • Alexander Mills
    Alexander Mills almost 5 years
    is uuid a built-in?
  • Alexander Mills
    Alexander Mills almost 5 years
    Has python ever worked? I get this ` File "<string>", line 1 import uuid; print uuid.uuid1() ^ SyntaxError: invalid syntax `
  • Joseph
    Joseph almost 5 years
  • abdusco
    abdusco almost 5 years
    Use python3 -c "import uuid; print(uuid.uuid4())" for python3