Shuffling Letters and Words
You can shuffle your feet and you can shuffle cards, but can you shuffle characters? Dave's latest column explores the possibilities.
My last few articles have described building a pretty sophisticated password generator, except for one thing: I never quite got to the point of scrambling the end result to add a second level of randomness. I sidestepped the issue by saying it was an exercise for the reader, but in fact, it's a pretty interesting problem, so let's look at it here.
You can reverse a word with the handy Linux command
rev, like so:
$ echo "hello from the other side" | rev edis rehto eht morf olleh
You also can reverse lines in a file so that the last line is shown first, penultimate line second, and so on:
$ cat -n test.me | sort -rn | cut -f2- entering along with him. enough to prevent a swirl of gritty dust from glass doors of Victory Mansions, though not quickly escape the vile wind, slipped quickly through the chin nuzzled into his breast in an effort to clocks were striking thirteen. Winston Smith, his It was a bright cold day in April, and the
You recognize that opening paragraph even though it's backwards, right? "Clocks were striking thirteen" can only be George Orwell's cautionary tale 1984.
Note: there's a Linux command called
tac that offers a reverse
would do the job too, but I've always loved
sort -rn as a
I wanted to demonstrate how to use it in a pipeline to accomplish the same
How about getting the lines of this file, but in completely random order?
There's a command for that—at least in Linux:
shuf. It's not
available on the Mac OS X command line, however, so if you're playing
along at home with your Mac system, well, you've just hit a road block.
Sorry about that. I offer an alternative at the end of this article
though, so don't despair!
If you're on a Linux system (and this is Linux Journal after all), then check this out:
$ cat test.me | shuf clocks were striking thirteen. Winston Smith, his entering along with him. glass doors of Victory Mansions, though not quickly escape the vile wind, slipped quickly through the enough to prevent a swirl of gritty dust from chin nuzzled into his breast in an effort to It was a bright cold day in April, and the
So those commands are all ready to go, but how about scrambling letters
in a line? That can be done with the
shuf command as
demonstrated previously, but
individual lines aren't quite ready for the
You can break up words by using the under-appreciated
fold command, like this:
$ echo "Winston" | fold -w1 W i n s t o n
Now that the word is broken down letter by letter into lines, the
command is ready to take on the task and randomize the lines (letters) as
$ echo "Winston" | fold -w1 | shuf n t i n o W s
Perfect. Now, there's one last step: stitching it all back together so it's a
word rather than a bunch of really short lines. Surprisingly perhaps, the
command is up for the task, because all you really need to do is get rid of the
newline character at the end of each line. Recall that the
instructs it to delete any occurrence of the specified letter.
So, here's the total command to shuffle the letters of a word:
$ echo "Winston" | fold -w1 | shuf | tr -d '\n' itoWnns$
Why is that
$ prompt tacked onto the shuffled word? Because the
invocation removes all newlines, even the one that otherwise would terminate
the final line. There are a couple ways around this, but the easiest is to
do something rather script-like. In fact, let's make this a tiny script:
$ cat scramble.sh #!/bin/sh # scramble - scramble whatever's specified on command line # usage: scramble word or phrase echo "$*" | fold -w1 | shuf | tr -d '\n' echo "" exit 0
I also could have used some intermediate variables, but as you can see, it's unnecessary in this case. It's easy, really, and now you can get some interesting results:
$ sh scramble.sh Winston Smith Shnoi tWstmin
Where this becomes particularly interesting is if you invoke it more than once with the same input. It should be different each time, correct? Turns out, it is:
$ sh scramble.sh Winston Smith nnih ttiWmoSs $ sh scramble.sh Winston Smith mnnWiosthS it $ sh scramble.sh Winston Smith nsmniott WhiS
That's exactly what was needed for the password generator, so now the script finally is done and ready to go with the addition of this simple script.And, If You Don't Have
So, what about those of you that aren't running Linux but are using
another *nix? There are a couple ways you can get the
shuf command or
its equivalent, one of which is to install the entire GNU coreutils package.
It turns out that Python also can duplicate the basic functionality
with a single line.
Yes, a single line:
python -c 'import sys, random; L = sys.stdin.readlines(); ↪random.shuffle(L); print "".join(L),'
Now, I don't know anything at all about Python, so I can't explain what's going on, but it's easy to verify that this does indeed work:
$ cat test.me | python -c 'import sys, random; L = ↪sys.stdin.readlines(); random.shuffle(L); print "".join(L),' entering along with him. clocks were striking thirteen. Winston Smith, his escape the vile wind, slipped quickly through the It was a bright cold day in April, and the enough to prevent a swirl of gritty dust from chin nuzzled into his breast in an effort to glass doors of Victory Mansions, though not quickly
Nice. Props to Cristian Ciupitu on superuser.com for this code snippet that I'm republishing here too.
And, now with all this randomness and shuffle alternatives, you might like to delve into the question of how random is random? Or maybe not. It turns out that's quite a sticky wicket and a rich area of computer science research.