Finishing Up the Content Spinner

Pick a Card, Any Card

The basic way to work with random numbers in Bash is to use the special $RANDOM variable. Each time it's referenced, it returns a randomly chosen number between 1 and MAXINT (32767). I constrain it to a specific range by using the modulus function, so this will generate a random number between 0 and MAXVALUE:

randomnum=$(( $RANDOM % $MAXVALUE ))

The double-parent notation triggers mathematical evaluation, but you already know that, right?

To make the bottom be the value 1 instead of zero, I just add a bit more math to the equation:

randomnum=$(( $RANDOM % $MAXVALUE + 1 ))

The script already can identify how many choices are in a specific cluster (for example, "{one|two|three}"), and now we have a simple one-liner to help randomly pick one of the values. The challenge, of course, is to pick the actual string value, not just show a number!

I know, I know—work, work, work.

Halfway through the spinline() function (which I'll show in its entirety in just a sec), $choices stores the count of how many options are in the cluster, and $source is the set of choices, minus the open and close curly brackets.

Here's my first attempt at the random word extraction:

pick=$(( $RANDOM % $choices ))
wordpick=$( echo $source | cut -d\| -f$pick )

But, that generates an error message when run. It's not because of a typo, however—it's legit to use cut and specify the pipe symbol as the field delimiter—but because I haven't compensated for the 0..n selection of the random number generator: request field -f0 from cut, and it complains because, well, there is no field zero.

That's easily fixed now that I understand the problem, however, and so here's version two:

pick=$(( $RANDOM % $choices + 1 ))
wordpick=$( echo $source | cut -d\| -f$pick )

Remember that modulus returns 0..(n-1) for its values, so when there are three choices, for example, $RANDOM % 3 returns 0, 1 or 2. Add one to each, and it's back on track with the values 1, 2 and 3.

With a few useful debugging lines, here's the function in its entirety:

function spinline()
  choices=$(grep -o '|' <<< "$*" | wc -l)
  choices=$(( $choices + 1 ))
  echo $choices options, spinning --- $source
  pick=$(( $RANDOM % $choices + 1 ))
  wordpick=$( echo $source | cut -d\| -f$pick )
  echo I pick choice $pick which is $wordpick

Yeah, code. Let's see what happens when I run it with the test sentence as input:

$ sh spinme.txt
3 options, spinning --- idea|concept|inspiration
I pick choice 2 which is concept
is that each time you'd use a
2 options, spinning --- word|phrase
I pick choice 1 which is word
you instead list a set of
3 options, spinning --- similar words|synonyms|alternative words
I pick choice 2 which is synonyms
and the software automatically picks one
2 options, spinning --- randomly|at random
I pick choice 2 which is at random
and is done.

It's close, actually—really close!


Dave Taylor has been hacking shell scripts for over thirty years. Really. He's the author of the popular "Wicked Cool Shell Scripts" and can be found on Twitter as @DaveTaylor and more generally at