Created
May 23, 2025 04:11
-
-
Save eevmanu/7f1a2df61ecfc1e4e2b0d002abdedb99 to your computer and use it in GitHub Desktop.
re-implement the uuid v7 uuid7 uuidv7 from uuidgen (part of https://github.com/util-linux/util-linux ) as version 2.41 using source code as context into bash shell script using gemini-2.5-pro-preview-05-06 in one shot
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/bin/bash | |
# Function to generate a UUID v7 string | |
# Implements the logic similar to libuuid's uuid_generate_time_v7 | |
uuid_generate_time_v7() { | |
local ms | |
local ts_hex | |
local rand_hex | |
local byte6_val byte8_val | |
local ver_char rand_a_part1 rand_a_part2 | |
local var_char rand_b_part1 rand_b_part2 rand_b_suffix | |
# 1. Get 48-bit timestamp in milliseconds (unix_ts_ms) | |
# GNU date specific for %N (nanoseconds) | |
if date +%s%N >/dev/null 2>&1; then | |
ms=$(( $(date +%s%N) / 1000000 )) | |
else | |
# Fallback for systems without %N (e.g., macOS default date) | |
# This will have lower precision for the millisecond part | |
# but is better than nothing. | |
local s | |
s=$(date +%s) | |
# Try to get microseconds if possible (e.g. gdate on macOS) | |
local us="000" # default to 000 milliseconds | |
if command -v gdate >/dev/null; then # GNU date on macOS | |
us=$(gdate +%N | cut -c1-3) # use first 3 digits of N for milli | |
elif [[ "$(uname)" == "Linux" ]]; then | |
# This case should ideally not be hit if the first date +%s%N failed | |
# but as a safeguard. | |
us=$(date +%N | cut -c1-3) | |
fi | |
ms=$(( s * 1000 + 10#$us )) # 10# to ensure base 10 for us | |
fi | |
# Format as 12 hex characters (6 bytes / 48 bits) | |
# Ensure it's exactly 12 characters, padding with leading zeros if necessary. | |
ts_hex=$(printf "%012x" "$ms") | |
# 2. Get 10 random bytes (for rand_a and rand_b parts) | |
# openssl is a good source of random hex. 10 bytes = 20 hex characters. | |
if command -v openssl >/dev/null; then | |
rand_hex=$(openssl rand -hex 10) | |
else | |
# Fallback if openssl is not available (less ideal, might be slower/less random quality) | |
# This generates 10 bytes, then converts to hex. | |
rand_hex=$(head -c 10 /dev/urandom | od -An -tx1 | tr -d ' \n' | sed 's/ //g') | |
# Ensure rand_hex is 20 characters long, pad if necessary (shouldn't be with od) | |
while ((${#rand_hex} < 20)); do rand_hex="0$rand_hex"; done | |
fi | |
# 3. Apply version (7) and variant (RFC 4122) | |
# Byte 6: (rand_hex characters 0-1) | |
# version = 7 (0111) | |
# uuid[6] = (rand_byte_6 & 0x0F) | 0x70 | |
byte6_val=$(( (0x${rand_hex:0:2} & 0x0F) | 0x70 )) | |
ver_char=$(printf "%x" "$(( (byte6_val & 0xF0) >> 4 ))") # Should be '7' | |
rand_a_part1=$(printf "%x" "$((byte6_val & 0x0F))") # Lower nibble of modified byte 6 | |
# Byte 7: (rand_hex characters 2-3) | |
# This is the rest of rand_a | |
rand_a_part2="${rand_hex:2:2}" | |
# Byte 8: (rand_hex characters 4-5) | |
# variant = 2 (10xx) | |
# uuid[8] = (rand_byte_8 & 0x3F) | 0x80 | |
byte8_val=$(( (0x${rand_hex:4:2} & 0x3F) | 0x80 )) | |
var_char=$(printf "%x" "$(( (byte8_val & 0xC0) >> 6 ))") # Should be 2 (binary 10) | |
# resulting hex will be 8,9,a,b | |
rand_b_part1=$(printf "%x" "$((byte8_val & 0x3F))") # Lower 6 bits of modified byte 8 | |
# Byte 9: (rand_hex characters 6-7) | |
# This is more of rand_b | |
rand_b_part2="${rand_hex:6:2}" | |
# Bytes 10-15: (rand_hex characters 8-19) | |
# The rest of rand_b | |
rand_b_suffix="${rand_hex:8:12}" | |
# 4. Assemble the UUID string | |
# xxxxxxxx-xxxx-Mxxx-Nxxx-xxxxxxxxxxxx | |
# M is version, N is variant | |
# Timestamp part 1 (8 hex chars) | |
# Timestamp part 2 (4 hex chars) | |
# Version (1 hex char from ver_char) + rand_a_part1 (1 hex char) + rand_a_part2 (2 hex chars) | |
# Variant (1 hex char from first nibble of byte8_val) + rand_b_part1 (1 hex char from second nibble of byte8_val) + rand_b_part2 (2 hex chars) | |
# Suffix (12 hex chars) | |
printf "%s-%s-%s%s%s-%s%s%s-%s\n" \ | |
"${ts_hex:0:8}" \ | |
"${ts_hex:8:4}" \ | |
"$ver_char" \ | |
"$rand_a_part1" \ | |
"$rand_a_part2" \ | |
"$(printf "%x" "$((byte8_val >> 4 & 0xF))")" \ | |
"$(printf "%x" "$((byte8_val & 0xF))")" \ | |
"$rand_b_part2" \ | |
"$rand_b_suffix" | |
} | |
# Example usage: | |
# uuid_generate_time_v7 | |
# for i in {1..5}; do uuid_generate_time_v7; done |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment