tags:

views:

101

answers:

5

I have a command which spouts a number of lines to stdout:

$ listall
foo
bar
baz

How do I extract a random entry from this, in a one-liner (preferably without awk) so I can just use it in a pipe:

$ listall | pickrandom | sed ... | curl ...

Thanks!

+8  A: 
listall | shuf | head -n 1
xiechao
Excellent, exactly what I needed (I didn't know about shuf) - thanks!
AnC
actually "listall | shuf -n 1" seems enough
xiechao
Not very portable: -bash: shuf: command not found
Idelic
+2  A: 

Using Perl:

  • perl -MList::Util=shuffle -e'print((shuffle<>)[0])'

  • perl -e'print$listall[$key=int rand(@listall=<>)]'

Alan Haggai Alavi
Thank you. While more complex than just using shuf, this might come in handy sometime.
AnC
+1  A: 

This is memory-safe, unlike using shuf or List::Util shuffle:

listall | awk 'BEGIN { srand() } int(rand() * NR) == 0 { x = $0 } END { print x }'

It would only matter if listall could return a huge result.

For more information, see the DADS entry on reservoir sampling.

Steven Huwig
Good to know, thanks! It's not a concern for this particular case, but I hadn't even thought of this issue before...
AnC
I added a link with more information. :)
Steven Huwig
+1  A: 

you can do it with just bash, without other tools other than "listall"

$ lists=($(listall)) # put to array
$ num=${#lists[@]} # get number of items
$ rand=$((RANDOM%$num)) # generate random number
$ echo ${lists[$rand]}
ghostdog74
Lots of great responses here - thanks!
AnC
A: 

Save the following as a script (randomline.sh):

#! /bin/sh
set -- junk $(awk -v SEED=$$ 'BEGIN { srand(SEED) } { print rand(), $0 }' | sort -n | head -1)
shift 2
echo "$@"

and run it as

$ listall | randomline.sh
Idelic