8

I am trying to print a random n letter word, where I input n from the command line itself, but for some reason my script is giving me the same answer every time when using the same value for n.

#!/bin/bash                                                                                                                                       
num=$1
egrep "^.{$num}$" /usr/share/dict/words | head -n $RANDOM| tail -n 1

I am calling my script like:

$ bash var3.sh 5
étude             # always the same output when using 5 

$ bash var3.sh 3
zoo               # always the same output when using 3

where var3.sh is the name of my script and 5 is the length of the word I want to print randomly.

How do I get it to print a truly random word?

4
  • 3
    $RANDOM is pretty likely to be greater than the number of n-letter words for most values of n (95.7% of the time for n = 3 for me). Commented Jun 12, 2018 at 8:46
  • Are you looking to print a random word completely, even if it isn't a word or print it randomly from the dict?
    – Xanmashi
    Commented Jun 12, 2018 at 8:52
  • If your task is related to security (for example to create a password), you should use a tool made for that task. Otherwise, it is possible to use shuf or sort -R as suggested in the answers. You can also use $RANDOM, but in a more advanced way. All these tools produce results that can be predicted (they are not truly random), but they are fast and good enough for many purposes.
    – sudodus
    Commented Jun 12, 2018 at 9:16
  • 1
    Maybe they use this method (obligatory XKCD reference)
    – molnarm
    Commented Jun 12, 2018 at 14:53

3 Answers 3

20

It doesn't. But $RANDOM returns big numbers (between 0 and 32767) which, especially for words of limited lengths, shows the same result, as the head portion probably returns all the results of the grep (for 3, there are only 819 matches in my /usr/share/dict/words).

Better solution might be to shuffle the results:

egrep "^.{$num}$" /usr/share/dict/words | sort -R | tail -n 1

where -R means --random-sort (a GNU sort extension).

2
  • 16
    Why tail? That made sense in OP's script, but since you're shuffling you could as well use head, and then sort should be able to detect the broken pipe and not bother shuffling the rest of the lines. Commented Jun 12, 2018 at 16:01
  • @PeterTaylor probably a good tip. Using tail is just a habit of mine... In the end, I'd probably prefer even more the shuf -n1, which is one pipe less... Commented Jun 14, 2018 at 11:45
19

A simple method to print an arbitrary num-letter word uses shuf:

egrep "^.{$num}$" /usr/share/dict | shuf -n1

The shuf command outputs a random permutation of the input, and the -n1 flag tells it to only output the first item from this result.

1
  • 3
    or grep -Ex ".{$num}". Or awk 'length == n' n="$num"'. Commented Jun 12, 2018 at 9:14
5

As others have pointed out, the main issue with your code is that $RANDOM more often than not is going to be a value much larger than then number of words of a certain length.

Using awk only:

$ awk -v len="$num" 'length == len { word[i++]=$0 }
                     END { print word[int(i*rand())] }' /usr/share/dict/words
Bosniac

The program reads in all lines from the given file that are of a certain length. These are stored in the array words.

At the end, a random element from this array is selected and printed.

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .