How to create a UUID in bash?

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,,} ]]

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:

  • UUID on Wikipedia.
  • FreeBSD Bug #186187 - [linprocfs] [patch] emulate /proc/sys/kernel/random/uuid

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.)


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

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