Ignacio
Ignacio

Reputation: 7928

Randomly select a file with a given extension and copy it to a given directory

I would like to write a simple bash script that randomly selects a .flac file from the /music/ folder (it will have to be recursive because there are many subfolders within that folder), and copy that file to /test/random.flac

This post is very close to what I want to do but I'm not sure how to change the script to do what I want.

I tried this:

ls /music |sort -R |tail -1 |while read file; do
    cp $file /test/random.flac
done

But I'm missing how to tell ls to do a recursive search of all the .flac inside the subfolders.

Upvotes: 0

Views: 1164

Answers (2)

Benjamin W.
Benjamin W.

Reputation: 52132

You can shove all the files into an array, then select one at a random index to move. This requires the globstar option to be enabled so you can use the **/* glob pattern:

shopt -s globstar
flacfiles=(/music/**/*.flac)
cp "${flacfiles[RANDOM % ${#flacfiles[@]}]}" /test/random.flac

To select a random index, we take $RANDOM modulo the number of elements in the flacfiles array.

If you want an error message in case the glob doesn't match anything, you can use the failglob shell option:

shopt -s globstar failglob
if flacfiles=(/music/**/*.flac); then
    cp "${flacfiles[RANDOM % ${#flacfiles[@]}]}" /test/random.flac
fi

This fails with an error message

-bash: no match: music/**/*.flac

in case there are no matching files and doesn't try to copy anything.

If you know for sure that there are .flac files, you can ignore this.

Upvotes: 3

Socowi
Socowi

Reputation: 27215

Recurse

Use find instead of ls:

find /music/ -iname '*.flac' -print0 | shuf -z -n1

The find part will find all flac files inside the directory /music/ and list them.
shuf shuffles that list and prints the first entry (which is random, because the list was shuffled).

-print0 and -z are there to use \NUL for separating the file names. Without these options, \n (newline) would be used, which is unsafe, because filenames can contain newlines (even though it is very uncommon).

Copy

If you want to copy just one random file, there's no need for a while loop. Use Substitution $() instead.

cp "$(find /music/ -iname '*.flac' -print0 | shuf -z -n1)" /test/random.flac

Upvotes: 3

Related Questions