Randomly Switching Upper and Lowercase in a Shell Script

Dave wraps up the shell-script L33t generator

Last time, I talked about what's known informally as l33t-speak, a series of letter and letter-pair substitutions that marks the jargon of the hacker elite (or some subset of hacker elite, because I'm pretty sure that real computer security experts don't need to substitute vowels with digits to sound cool and hip).

Still, it was an interesting exercise as a shell-scripting problem, because it's surprisingly simply to adapt a set of conversion rules into a sequence of commands. I sidestepped one piece of it, however, and that's what I want to poke around with this article: changing uppercase and lowercase letters somewhat randomly.

This is where "Linux Journal" might become "LiNUx jOurNAl", for example. Why? Uhm, because it's a puzzle to solve. Jeez, you ask such goofy questions of me!

Breaking Down a Line Letter by Letter

The first and perhaps most difficult task is to take a line of input and break it down letter by letter so each can be analyzed and randomly transliterated. There are lots of ways to accomplish this in Linux (of course), but I'm going to use the built-in Bash substring variable reference sequence. It looks like this:


${variable:index:length}

So to get just the ninth character of variable input, for example, I could use ${input:9:1}. Bash also has another handy variable reference that produces the length of the value of a particular variable: ${#variable}. Put the two together, and here's the basic initialization and loop:


input="$*"
length="${#input}"

while [ $charindex -lt $length ]
do
    char="${input:$charindex:1}"
    # conversion occurs here
    newstring="${newstring}$char"
    charindex=$(( $charindex + 1 ))
done

Keep in mind that charindex is initialized to 0, and newstring is initialized to "", so you can see how this quickly steps through every character, adding it to newstring. "Conversion occurs here" is not very exciting, but that's the placeholder you need.

Lower, Meet Upper, and Vice Versa

Last time I also showed a quick and easy way to choose a number 1–10 randomly, so you can sometimes have something happen and other times not happen. In this command:


doit=$(( $RANDOM % 10 ))       # random virtual coin flip

Let's say there's only a 30% chance that an uppercase letter will convert to lowercase, but a 50% chance that a lowercase letter will become uppercase. How do you code that? To start, let's get the basic tests:


if [ -z "$(echo "$char" | sed -E 's/[[:lower:]]//')" ]
then
   # it's a lowercase character
elif [ -z "$(echo "$char" | sed -E 's/[[:upper:]]//')" ]
then
   # it's uppercase
fi

This is a classic shell-script trick: to ascertain if a character is a member of a class, replace it with null, then test to see if the resultant string is null (the -Z test).

The last bit's easy. Generate the random number, then if it's below the threshold, transliterate the char; otherwise, do nothing. Thus:


if [ -z "$(echo "$char" | sed -E 's/[[:lower:]]//')" ]
then
  # lowercase. 50% chance we'll change it
  if [ $doit -lt 5 ] ; then
    char="$(echo $char | tr '[[:lower:]]' '[[:upper:]]')"
  fi
elif [ -z "$(echo "$char" | sed -E 's/[[:upper:]]//')" ]
then
  # uppercase. 30% chance we'll change it
  if [ $doit -lt 3 ] ; then
    char="$(echo $char | tr '[[:upper:]]' '[[:lower:]]')"
  fi
fi

Put it all together and you have this Frankenstein's monster of a script:


$ sh changecase.sh Linux Journal is a great read.
LiNuX JoURNal is a GrEaT ReAd.
$ !!
LINuX journAl IS a gREat rEAd
$

Now you're ready for writing some ransom notes, it appears!

Dave Taylor has been hacking shell scripts on UNIX and Linux systems for a really long time. He's the author of Learning Unix for Mac OS X and Wicked Cool Shell Scripts. You can find him on Twitter as @DaveTaylor, and you can reach him through his tech Q&A site: Ask Dave Taylor.

Load Disqus comments