0

I have a random set of files that I want to loop over (e.g. so I can copy or move). I am using the command shuf using a bash function.

inclnm customarily contains a wildcard for specific files, e.g.

( -name A\* -o -name B\*.mse ).

Here is the random listing command that I would like to loop through.

shuf -n $nf < <( find $dpath -maxdepth 1 -type f "${inclnm[@]}" )
Nigel
  • 39
  • 4
  • 2
    And the problem is? – Barmar Sep 04 '21 at 07:21
  • Pipe the output of `shuf` to a `while read filename` loop – Barmar Sep 04 '21 at 07:22
  • Or pipe it to `xargs` to pass them all as arguments to another command. – Barmar Sep 04 '21 at 07:23
  • Thought about a `for fl in $( shuf ... ); do`. But there could be more sensible way. With the for loop, the find must run to completion, and I can overrun the command line arguments. – Nigel Sep 04 '21 at 07:42
  • Piping to `while read` is best in case filenames contain spaces. It only fails if filenames contain newlines. – Barmar Sep 04 '21 at 07:43
  • Thanks. Have noticed that with a pipe at end of line, I do not need continuation line. – Nigel Sep 04 '21 at 08:40
  • Does this answer your question? [How can I select random files from a directory in bash?](https://stackoverflow.com/questions/414164/how-can-i-select-random-files-from-a-directory-in-bash) – Léa Gris Sep 04 '21 at 09:08

1 Answers1

0

The most rebust option is using null delimited records:

#!/usr/bin/env bash

dpath=./
nf=10
inclnm=( -name a\* -o -name b\* )

mapfile -d '' random_files < <(
  find "$dpath" -maxdepth 1 -type f "${inclnm[@]}" -print0 |
  shuf -z -n "$nf"
)

# Debug
declare -p random_files

Or alternatively replacing find with printf:

inclnm=( a* b* )

cd "$dpath" || :
mapfile -d '' random_files < <( printf %s\\0 "${inclnm[@]}" | shuf -z -n "$nf" )

Or even better, let shuf work on arguments directly and no need for printf or find:

mapfile -d '' random_files < <( shuf -z -n "$nf" -e "${inclnm[@]}" )

Note that this last method will be subject to the max argument length restriction.

Léa Gris
  • 17,497
  • 4
  • 32
  • 41