Generate CUIDs in Bash

Resources  |  Generate CUIDs in Bash

Generating a CUID (Collision-resistant Unique Identifier) in Bash is more complex compared to higher-level languages because Bash lacks built-in functions for some of the necessary operations, like generating random bytes or hashing. However, we can use external utilities like date, openssl, and hexdump to achieve this.

Here is a step-by-step guide to generating a CUID in Bash:

Steps to Generate a CUID in Bash

  1. Timestamp: Use the current timestamp to ensure uniqueness over time.
  2. Counter: Implement a simple counter mechanism.
  3. Fingerprint: Use machine-specific values to avoid collisions.
  4. Randomness: Add random characters to further reduce the risk of collisions.
  5. Base36 Encoding: Encode the components using Base36 for readability.

Example Script

#!/bin/bash

# Base36 encoding function
encode_base36() {
    local number=$1
    local base36_chars="0123456789abcdefghijklmnopqrstuvwxyz"
    local result=""
    while [ "$number" -gt 0 ]; do
        local remainder=$((number % 36))
        result="${base36_chars:$remainder:1}$result"
        number=$((number / 36))
    done
    echo "$result"
}

# Get current timestamp in milliseconds
timestamp=$(date +%s%3N)

# Simple counter mechanism
counter_file="/tmp/cuid_counter"
if [ ! -f "$counter_file" ]; then
    echo 0 > "$counter_file"
fi
counter=$(cat "$counter_file")
counter=$((counter + 1))
echo "$counter" > "$counter_file"

# Machine-specific fingerprint (MD5 hash of hostname)
fingerprint=$(hostname | md5sum | cut -c1-4)

# Generate a random string of 4 characters
random=$(openssl rand -hex 2)

# Encode components in Base36
timestamp_base36=$(encode_base36 $timestamp)
counter_base36=$(encode_base36 $counter)

# Combine components to form the CUID
cuid="c${timestamp_base36}${counter_base36}${fingerprint}${random}"
echo "$cuid"

Explanation

  1. Base36 Encoding:

    • The encode_base36 function converts a decimal number to a Base36 encoded string.
  2. Timestamp:

    • timestamp=$(date +%s%3N) gets the current timestamp in milliseconds.
  3. Counter:

    • The counter value is stored in a temporary file /tmp/cuid_counter and is incremented each time a new CUID is generated.
  4. Machine Fingerprint:

    • The hostname | md5sum | cut -c1-4 command generates a machine-specific fingerprint by hashing the hostname and taking the first 4 characters.
  5. Random String:

    • openssl rand -hex 2 generates a 4-character random string.
  6. Combine Components:

    • The c${timestamp_base36}${counter_base36}${fingerprint}${random} line combines the components to form the final CUID.

Summary

This script provides a basic implementation of generating a CUID in Bash. It uses external commands to handle timestamp generation, random number generation, and hashing, while a simple function handles Base36 encoding. This approach ensures that the generated CUIDs are unique, readable, and collision-resistant.