There are a few "XKCD password" generators out there, but the task seems so straight forward, so I wanted a compact and simple solution. My requirements were:

  • One-line alias (or few-line function) to put in .profile
  • Standard Unix commands (require no packages)
  • Column output (like pwgen)
  • Titlecase words (for readability)

(I'm happy to renounce command line options in exchange for simplicity.)

for i in {1..32}; do grep -E "^[a-z]{4,8}$" /usr/share/dict/words | gshuf -n4 | gsed 's/.*/\u&/' | tr -d '\n' | awk '{print $1}'; done | column

Current problems:

  • shuf requires brew install coreutils on macOS (which I also use)
  • sed requires brew install gnu-sed (ditto)
  • tr -d '\n' | awk '{print $1}' seems silly.

How can I make a short, yet readable command line that works on both Linux and macOS?

On a side note I found that by using SCOWL, which has a range from short word lists with common names to long word lists with obscure words, you can trade-off memorability Vs. entropy.

  • That pipeline is still a bit too long to write each time again, so you're probably going to have to copy it from somewhere. Is there a reason not to use (say) a Perl script? I think OSX has Perl. – ilkkachu Apr 27 '17 at 12:51
  • Shuf derives randomness from /dev/urandom by default which is the preferred random source on UNIX systems. While not "truly random", it should be the best option your computer will likely allow, so unless your system is missing that device, there should be no worries in that regard. To avoid installing coreutils, you can try and tap into /dev/urandom yourself. Personally, the main risk with your approach that I see is that if the perpetrator gets to taper with ANY standard tool in your chain or the dictionary you're using, or replace $PATH, all your passwords will be compromised. – undercat applauds Monica Apr 27 '17 at 16:34
  • The primary question was how to accomplish the same result with a shorter and better command line, and without using non-standard GNU-commands. (The random issue is another issue.) – forthrin Apr 27 '17 at 17:03
  • I could of course make something in PHP, which is my main language, but I'm trying to learn more elegant Unix, and this seemed like a good occasion. – forthrin Apr 27 '17 at 17:14

I don't have access to my Mac from where I am, but since it's running OS X 10.4.11, I'm not sure it would be comparable to your environment. The following works to generate a single password on FreeBSD. If this does not meet your needs, feel free to let me know what it lacks in the comments:

(sort -R /usr/share/dict/words                                   \
 | head -n 4                                                     \
 | awk '{ sub(".", substr(toupper($0),1,1)); printf "%s", $0 }'  \
 ; echo)

On FreeBSD and on my Arch Linux system, sort -R randomly orders the input. It is only pseudo-random, but that's as good as you're going to get with most other programs as well. Then choose four words from that set with head. Rather than GNU sed, awk can be used to capitalize the first character of each line. Finally, echo is used to place the terminating newline. This is all in a subshell for easier inclusion in a loop, pipe, or other construct.

  • 1
    sort -R doesn't exist on macOS, so I found a generic shuffle snippet which then adds up to: cat /usr/share/dict/words | perl -MList::Util -e 'print List::Util::shuffle <>' | head -n 4 | awk '{ sub(".", substr(toupper($0),1,1)); printf "%s", $0 }'; echo. So it now works without extra packages, but how to make it more short and elegant? – forthrin Apr 27 '17 at 17:37
  • @forthrin If you need to resort to Perl, I feel that a better solution would be entirely in Perl. I will leave that to someone who uses that language more than I do. Typically for these things, I make a script in ~/bin, which is at the head of my $PATH. Then, instead of typing out a long pipe, I'd just call mkpw or similar – Fox Apr 27 '17 at 17:41
  • Found some Python example, though most of them require Python 3. The example that works in 2.7 prints a literal array which can't be used as a password. groups.google.com/forum/m/#!msg/comp.lang.python/YhlOSOBi9Pk/… – forthrin Apr 27 '17 at 17:45
  • @forthrin If you want the shortest way to do this, you might hit up Code Golf – Fox Apr 27 '17 at 17:46
  • 1
    @Fox Fisher-Yates shuffle doesn't say anything about the quality of the RNG, it's only the part about turning a bit stream into a permutation. Perl's List::Util::shuffle calls rand, which 1. uses a PRNG designed for speed, for things like non-competitive games and numerical simulations, not for security applications; and 2. is not seeded from good entropy so can be quite predictable. I looked it up the last time this came up. – Gilles 'SO- stop being evil' Apr 27 '17 at 22:01

Not the answer you're looking for? Browse other questions tagged or ask your own question.