How can I select random files from a directory in bash?
Here's a script that uses GNU sort's random option:
ls |sort -R |tail -$N |while read file; do
# Something involving $file, or you can leave
# off the while to just get the filenames
done
Here are a few possibilities that don't parse the output of ls
and that are 100% safe regarding files with spaces and funny symbols in their name. All of them will populate an array randf
with a list of random files. This array is easily printed with printf '%s\n' "${randf[@]}"
if needed.
This one will possibly output the same file several times, and
N
needs to be known in advance. Here I chose N=42.a=( * ) randf=( "${a[RANDOM%${#a[@]}]"{1..42}"}" )
This feature is not very well documented.
If N is not known in advance, but you really liked the previous possibility, you can use
eval
. But it's evil, and you must really make sure thatN
doesn't come directly from user input without being thoroughly checked!N=42 a=( * ) eval randf=( \"\${a[RANDOM%\${#a[@]}]\"\{1..$N\}\"}\" )
I personally dislike
eval
and hence this answer!The same using a more straightforward method (a loop):
N=42 a=( * ) randf=() for((i=0;i<N;++i)); do randf+=( "${a[RANDOM%${#a[@]}]}" ) done
If you don't want to possibly have several times the same file:
N=42 a=( * ) randf=() for((i=0;i<N && ${#a[@]};++i)); do ((j=RANDOM%${#a[@]})) randf+=( "${a[j]}" ) a=( "${a[@]:0:j}" "${a[@]:j+1}" ) done
Note. This is a late answer to an old post, but the accepted answer links to an external page that shows terrible bash practice, and the other answer is not much better as it also parses the output of ls
. A comment to the accepted answer points to an excellent answer by Lhunath which obviously shows good practice, but doesn't exactly answer the OP.
You can use shuf
(from the GNU coreutils package) for that. Just feed it a list of file names and ask it to return the first line from a random permutation:
ls dirname | shuf -n 1
# probably faster and more flexible:
find dirname -type f | shuf -n 1
# etc..
Adjust the -n, --head-count=COUNT
value to return the number of wanted lines. For example to return 5 random filenames you would use:
find dirname -type f | shuf -n 5