If you're set on using arc4random it's no big deal to use ctypes to invoke it from Python. Bash is quick to bang out but it's funny how your parent needs to compile a C program then invoke it N times per bash script run. Using Python for this is an obvious choice.
Yes thanks for pointing that out, I wrote a slightly faster version below. I took your advice and wanted just a single invoke on the C program, so I modified it to take an argument. I'm satisfied!
> cat arc4random-v2.c
#include <stdio.h>
#include <stdlib.h>
int main(int argc, char** argv) {
if ( ! (argc == 1 || argc == 2) ) {
printf("usage: %s [n_output]\n", argv[0]);
} else {
int n_iter = (argc == 2) ? atoi(argv[1]) : 1;
for (int i = 0; i < n_iter; i++) {
printf("%u\n", arc4random());
}
}
return 0;
}
> ./arc4random 3
4282823399
333796506
762478899
> cat pwgen-v2.sh
#!/usr/bin/env bash
dict=/usr/share/dict/words
n=4 # of words to include in passphrase
nl=$(wc -l $dict | sed 's_[ \t]*\([0-9]*\).*_\1_')
fmt_flag() { echo $[$1 % $nl] | sed -n -e 's_^_-e _' -e 's_$_p_p' ; }
flags=$(./arc4random $n | while read -r i; do fmt_flag "$i"; done)
words=$(sed -n $flags < $dict)
echo $words
> time ./pwgen.sh
liparite evade retiringly spacious
real 0m0.268s
user 0m0.251s
sys 0m0.015s
> time ./pwgen-v2.sh
latherin prideling thumbscrew unraveled
real 0m0.082s
user 0m0.072s
sys 0m0.013s
EDIT: note that the single call to sed results in alphabetical/dictionary-dependent results... (!) oops