185

In Java it is possible to create a random UUID:

UUID uuid = UUID.randomUUID();

How to do this in Bash?

030
  • 5,731
  • 12
  • 61
  • 107
raoulsson
  • 4,633
  • 10
  • 32
  • 29

14 Answers14

224

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,,} ]]
Samveen
  • 1,839
  • 1
  • 14
  • 19
Dennis Williamson
  • 60,515
  • 14
  • 113
  • 148
  • 7
    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) – quack quixote Jan 16 '10 at 14:05
  • uuidgen comes builtin on freeBSD. it isn't always in the e2fsprogs package. – Good Person May 22 '14 at 01:58
  • 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. – Rob Jul 10 '14 at 20:55
  • 1
    @Rob: To answer your original question, it's for [drive labels](https://help.ubuntu.com/community/UsingUUID). – Dennis Williamson Jul 10 '14 at 21:45
  • 2
    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. – David Oct 14 '15 at 18:27
  • 1
    @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,,} ]]` – Dennis Williamson Oct 14 '15 at 19:30
  • Dennis, would you add the information that `uuidgen` is part of the base system for all bsd derivatives (other than `openbsd`) to you answer? – Samveen Oct 15 '15 at 08:28
  • Ummm I just want to know how to install one of these on macos or linux...pls – Alexander Mills May 23 '19 at 05:43
167

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:

Samveen
  • 1,839
  • 1
  • 14
  • 19
  • 19
    This is awesome. – Tom O'Connor Aug 07 '13 at 13:55
  • 3
    This should be avoided as it is highly non-portable (although FreeBSD supplies /compat/linux/proc/sys/kernel/random/uuid for poorly written applications) – Good Person May 22 '14 at 01:58
  • 1
    It fits perfectly for usage inside of initrd image – Maximilian Jun 04 '15 at 16:08
  • 1
    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 Oct 14 '15 at 18:25
  • @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. – Samveen Oct 15 '15 at 06:48
  • 2
    This should be the best answer! – dguerri Feb 10 '16 at 00:14
  • 6
    This is a better answer for really minimal setups, like a Docker container. – jacderida Jul 13 '16 at 19:35
34

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

quack quixote
  • 1,665
  • 14
  • 17
  • 7
    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. – user1686 Jan 16 '10 at 15:08
  • same works on Fedora-25, too ... – kmonsoor Oct 23 '17 at 11:29
20

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
noway
  • 311
  • 2
  • 4
  • 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 May 22 '14 at 14:08
  • 1
    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`. – Dennis Williamson May 22 '14 at 17:47
  • put it online at a url so people can source it and try it `source <(curl url)` or whatever – MrCholo May 23 '19 at 05:57
19

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
dan
  • 321
  • 2
  • 6
  • 1
    Brilliant! just a single line with no dependencies, BSD/macOS compatible... great – dinigo Jan 10 '17 at 08:00
  • 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. – UncaAlby Jan 18 '18 at 19:09
  • 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. – dan Jan 19 '18 at 23:11
  • 2
    Do **not** use this, it completely violates the UUID specification. Only version 4 UUID are allowed to be random like this. – jlh May 14 '18 at 15:08
  • 3
    @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}'` – Stuart P. Bentley Sep 29 '18 at 17:33
14

Just so python doesn't feel left out:

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

To use it in the shell:

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

See the Python Documentation UUID for the kinds of UUIDS that can be generated.

To generate a systemd machine-id compatible file on a non-systemd machine, you could use python to do it this way:

python -c 'import re; import uuid; print re.sub("-","",str(uuid.uuid4()))' \
 > /etc/machine-id
Waddles
  • 3
  • 2
gm3dmo
  • 9,632
  • 1
  • 40
  • 35
11

Perl provides a UUID library based on the e2fsprogs package. On my Debian system it's the libuuid-perl package. Here's an example one-liner; see man uuid for more:

$ 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

This would be trivial to add to a shellscript with backticks or $() notation:

#!/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
  • 1,665
  • 14
  • 17
3
apt-get install uuid

Worked for me, then i did run uuid

Joseph
  • 201
  • 2
  • 3
1

I wrote a little Bash function using Python to generate an arbitrary number of UUIDs in bulk:

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

If you prefer lowercase, change:

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

To:

python -c 'import uuid; print("\n".join([str(uuid.uuid4()) for x in range('"$count"')]))'
Will
  • 1,127
  • 10
  • 25
1

Please look at the OSSP UUID library (http://www.ossp.org/pkg/lib/uuid/), and consider installing it. Some projects offer it as an option (e.g. PostgreSQL). It properly handles version 3 and version 5 UUIDs, which was beyond what my installed (e.g. e2fsprogs) library could handle. Fortunately, openSUSE has it in one of the main repos. Getting a version to work w/ Windows (e.g. Cygwin) or MySQL has been a flail. Looks like it is time to switch to Linux/PostgreSQL/Python (and I so loved the SQLyog GUI to MySQL/MariaDB) since I really need v3 and v5 UUIDs.

  • Agree completely! For my use case it was perfect as it also supports namespacing via the `-v3 ns:URL custom-data` seeding mechanism. – Roberto Andrade Oct 06 '15 at 18:09
1

I'm sure some will arrive here, and are just looking for an easy way to generate a unique ID for use in their scripts, and it doesn't need to be a true UUID.

If so, you can just do the following, which will generated a id that's unique down to the second - so if you run this multiple times within a second, you'll still get the same result.

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

will generate ids like the following based off the current system time:

U1454423662

NOTE: If you're on Linux, or have Coreutils installed on a mac, then you can use the following to generate a unique id to the nanosecond:

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

or if you prefer a python based solution down to the nanosecond, which should work almost everywhere, run:

MYUID=U$(python -c'import time; print repr(time.time())')
echo $MYUID
Brad Parks
  • 674
  • 13
  • 19
  • 1
    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)"` – Chris Harrington Aug 21 '16 at 14:08
  • Hey... good points on the only unique to the second point... I'll add some notes above... – Brad Parks Aug 21 '16 at 23:22
1

This thread, with it's varied examples, was really useful to me. I frequently need uuid functions from a number of different environments. And while I love the pure bash examples, it's sometimes more convenient to use a library from a different language.

So just for thoroughness, ruby (1.9.3+) has the built-in SecureRandom module containing a number of useful hash and id functions. From the bash cli, you can do this.

ruby -r securerandom -e 'puts SecureRandom.uuid'
wbr
  • 19
  • 1
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`
Michael Hampton
  • 237,123
  • 42
  • 477
  • 940
  • 3
    A bit more explanation would help your answer – Dave M Jun 18 '18 at 11:58
  • 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 Jun 25 '18 at 10:26
  • 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 – andyfff Jun 25 '18 at 10:28
-1

If you are using Java 10.

$ jshell
jshell> import java.util.*
jshell> String id = UUID.randomUUID().toString();
amit
  • 9
  • Java 10 is not bash. – kasperd Sep 12 '18 at 06:27
  • 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? – amit Sep 18 '18 at 14:05
  • 1
    @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. – Samveen Sep 27 '18 at 03:59
  • 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/Contents/Home/bin/jshell -s | grep -v ">"` But it is a lot more long winded than `uuidgen`. – mlk Mar 05 '19 at 14:00