3

For start, we know how can we output random lines from a txt file:

perl -MList::Util -e 'print List::Util::shuffle <>' words.txt

But we need a general solution (perl is usually installed on every unix-like OS) to output 4 random words from a txt file, how can we do it?

$ cat words.txt
...
alpha
beta
gamma
delta
epsilon
...
$

The "..." represents many other words.

Example output (without newline between them, but one unix newline is needed at the end, spaces should separate them):

$ perl SOMEMAGIC words.txt
gamma alpha delta beta
$

Using only perl, the shortest possible solution (oneliner).

It will be used as human memorable password generator: https://xkcd.com/936/

Since afaik perl is enough good to be named "random generator".

Example common english wordlist with 32768 unique lines: https://pastebin.ubuntu.com/23726760/

  • Did you mean to post this on Code Golf? – Michael Homer Jan 1 '17 at 21:09
  • 6
    Otherwise, this feels like a general programming question (and so belonging on Stack Overflow), but it's also structured as a lazy "write my program" question that probably wouldn't be well-received. – Michael Homer Jan 1 '17 at 21:10
4

Perl is actually not such a good tool for this because you need a third-party library to generate random numbers securely. The default random number generator (rand or anything else that uses the same source, such as List::Util::shuffle) is not suitable for anything related to security. If you want to use Perl, install Math::Random::Secure (and its dependencies) (perl -MCPAN -eshell and run install Math::Random::Secure).

perl -MMath::Random::Secure=rand -l -e '@words = <>; print map $words[rand(@words)], 1..4' words.txt

I suggest using Python instead. These days it's about as common as Perl, and its standard library is much better rounded. Yes, the code is longer, but short code is not in itself a sign of quality.

python -c 'import random, sys; rng = random.SystemRandom(); words = sys.stdin.readlines(); print " ".join([words[rng.randrange(0, len(words))][:-1] for i in xrange(4)])' <words.txt

In a more readable multi-line form:

import random, sys
rng = random.SystemRandom()
words = sys.stdin.readlines()
print " ".join([words[rng.randrange(0, len(words))][:-1] for i in xrange(4)])

Alternatively, if you have non-antique GNU coreutils, which is the case on non-embedded Linux and Cygwin, you can use the shuf utility. You need to pass a secure random generator with the --random-source option.

shuf --random-source=/dev/urandom -r -n 4 words.txt
  • testing the python oneliner, many-thanks! – halajoe Jan 2 '17 at 9:09
2

It sounds like you're not against non-Perl solutions, you just want something that works on most systems. In that case, the following uses only GNU core utils:

sort -R --random-source=/dev/urandom words.txt | head -n4 | paste -s -d' '

Modified to use shuf, based on Gilles' suggestion:

shuf -n 4 -r words.txt | paste -s -d' '
  • 1
    If you're going to rely on GNU coreutils, you might as well use shuf instead of this complex, slow pipeline. Using sort even introduces a small undesirable bias because it forbids repetition. – Gilles Jan 1 '17 at 23:41
  • You need to pass --random-source with shuf as well. The default RNG is not seeded reliably. – Gilles Jan 2 '17 at 0:58
  • "sort -R" is not random! try it with a testfile like: printf '1\n1\n2\n2\n' > a.txt – halajoe Jan 2 '17 at 9:04
  • 1
    @halajoe sort -R is random (but with poorly-seeded entropy unless --random-source points to a good RNG) for inputs without duplicates. – Gilles Jan 2 '17 at 12:43
1

(ignoring the security problem mentioned by @Gilles)

 perl -0nE '@a=split; say join(" ", map{ $a[rand @a] } 1..4)'

or if you like CamelCase...

 perl -0nE '@a=split; say map{ ucfirst $a[rand @a] } 1..4'
  • Since you're mentioning "security problems", maybe you should point these out? It would help others if you additionally explained what the code is doing. – Kusalananda Jan 2 '17 at 12:39
  • 2
    @Kusalananda The security problem is the one I mention in my answer: Perl's rand is not a secure RNG. – Gilles Jan 2 '17 at 12:44

Your Answer

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

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