As more fully detailed in my question here, I'm in the process of starting a small, local business and wanted to avoid showing sequential invoice IDs to clients, and instead generate completely random ones. Thanks to the advice in the comments to that question, I decided to eliminate the risk of any collisions by incorporating logic that checks against a database (a flat text file) of all IDs that have previously been generated.

This is my attempt at doing so, which to my amazement is functional, but probably not as robust as it could be. Since then I have also decided on using 5-digit numbers, as these look better to me and a limit of 99,000 transactions (without 00000, and I might even exclude the first 10,000 digits through to 09999) will be more than enough for me, and the logic of the script means that collisions should no longer be an issue.

#!/usr/bin/env bash

generate_num() {
num=$(head /dev/urandom | tr -dc '[:digit:]' | cut -c 1-5)

read -p "Are you sure you want to generate a new invoice ID? [Y/n] " -n 1 -r
if [[ $REPLY =~ ^[Yy]$ ]]
    generate_num && echo Generating a random invoice ID and checking against database...
    sleep 2

    while grep -xq "$num" "ID_database" 
            echo Invoice ID \#$num already exists in database...
            sleep 2
            generate_num && echo Generating new random invoice ID and checking against database...
            sleep 2

    echo Generated random invoice ID \#$num
    sleep 1
    echo Invoice ID \#$num does not exist in database...
    sleep 2
    echo $num >> "ID_database" && echo Successfully added Invoice ID \#$num to database...

I have two main questions I'd like answered about it.

  1. Can the code itself be improved on? This is one of the few Bash scripts I've ever written the core logic for, and perhaps the most involved, so if there's anything I shouldn't be doing or anything I could do better, I'd appreciate this.

  2. Would it be conceivable to move the "database" into the script file itself, thus avoiding the need to maintain two separate files? If not, what are the reasons for this?

Thank you in advance, I'd appreciate some help from those more experienced with Bash than I am.

  • \$\begingroup\$ Just a thought: Why not using UUIDs as invoice IDs? That would prevent you from the hassle to check if these already exist in your database. \$\endgroup\$ – πάντα ῥεῖ Jun 25 '20 at 16:12
  • \$\begingroup\$ @πάνταῥεῖ I want something that's nice and short to be more aesthetically appealing and memorable to clients and fit on the invoice, hence the 5 digit limit. \$\endgroup\$ – Hashim Aziz Jun 25 '20 at 16:18

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Browse other questions tagged or ask your own question.