Passphrase generator script Below script is used to generate passphrases for gpg (or anything really).

Do you see any blatant security mistakes in it?

I wrote it by myself, because I couldn't find any passphrase generator that doesn't use external services and uses /dev/urandom.

Note: I run it with ./generator.bash 4 &gt; x &amp;&amp; vim x so stdout is not printed to the terminal, but I'm not sure if this is neccessary. I'm thinking that somewhere terminal history could be stored.

#!/bin/bash
# Usage: ./passphrase_gen.bash 4 &gt; x &amp;&amp; vim x
# We redirect to file and print via vim so no history is saved anywhere.
# Repeat after you get passphrase you like. Memorize it/write it down
# and remove x afterwards.
set -eo pipefail

words=/usr/share/dict/words

# https://serverfault.com/a/214620/216850
sudo rngd -r /dev/urandom

n=$1

# print $n randomly chosen words from $words file
for i in $(seq 1 $n); do
  # https://unix.stackexchange.com/a/268960
  random=$(od -vAn -N4 -tu4 &lt; /dev/urandom)

  lines=$(cat $words | wc -l)

  line=$((random % lines))
  awk "NR==$line" $words
done


Gist link: https://gist.github.com/jan-swiecki/9974501047c79bad12a3c87cfe846cd6
Note: I run it with ./generator.bash 4 &gt; x &amp;&amp; vim x so stdout is not printed to the terminal, but I'm not sure if this is neccessary. I'm thinking that somewhere terminal history could be stored.


I don't think this is necessary.
If anything, you might forget to remove x,
which could be a security risk.

Avoid seq

seq is not a standard tool, and a native alternative exists:

for ((i = 0; i &lt; n; i++)); do ...; done


Extract constants out of loops

This statement is executed in each iteration of the loop:


lines=$(cat $words | wc -l)



But the content of the $words file is likely constant,
so it's safe to compute this once, before entering the loop.

Unnecessary cat

The cat command is unnecessary with wc, it's better to redirect input:


lines=$(wc -l &lt; "$words")



Double-quote variables in command line arguments

Although the content of $words doesn't contain spaces,
as a good practice it's good to double-quote it when using as program arguments, for example instead of:


awk "NR==$line" $words



Write:

awk "NR==$line" "$words"


Arithmetic context

Instead of this:


line=$((random % lines))



You can write simpler:

((line = random % lines))