3

I want to execute one command for every file in a folder, but randomly. Something like:

find . -type f -exec <command> '{}' \;

but every time in another order. This is closest to my needs, but 1) it doesn't work, 2) order is random, but always the same:

find . -type f -print0 | sort -Rz | xargs -0 <command>
  • 1
    Do you realize that the same command will get run on every file, simply in a different order? – Julie Pelletier Aug 26 '16 at 19:05
  • 2
    That command should work. What's wrong with it? Are you sure that the command isn't reordering the files? What's the output of find . -type f -print0 | sort -Rz | xargs -0 echo, does it change if you run it multiple times? – Gilles 'SO- stop being evil' Aug 26 '16 at 22:36
  • Hmm indeed... when I use echo command, it works as expected. But actually I want <command> to be mupdf (I want to display images from folder in random order) - in that case it only displays randomly selected image and exits. Same with executable script with only one command echo "$1" in it - only first file name is echoed. When I use my first commandline: find . -type f -exec <command> '{}' \; , all images are displayed in sequence (when I close one image, next image is displayed), but not in random order. – Maciek Łoziński Aug 29 '16 at 17:01
1
find . -type f -exec <command> '{}' \;

is not equivalent to

find . -type f | xargs <command>

observe:

$ find -type f
./b
./c
./e
./d
./a
$ find -type f -exec echo '{}' \;
./b
./c
./e
./d
./a
$ find -type f | xargs echo
./b ./c ./e ./d ./a

xargs collects a bunch of arguments up to a given length and then executes the command with all arguments at once.

This is what gets executed from find -type f -exec echo '{}' \;

echo ./b
echo ./c
echo ./e
echo ./d
echo ./a

This is what gets executed from find -type f | xargs echo

echo ./b ./c ./e ./d ./a

This works well for commands that can take multiple arguments like md5sum or file. But does not work for commands that only take one argument at a time.

To make xargs behave more like find -exec you can add argument -n1 to xargs:

$ find -type f | xargs -n1 echo
./b
./c
./e
./d
./a

-n1 tells xargs to execute a command for every 1 arguments.

In your example command:

find . -type f -print0 | sort -Rz | xargs -0 -n1 <command>

Bonus: you can also make find -exec to behave more like xargs by closing the -exec with \+ instead of \;:

find -type f -exec <command> '{}' \+
| improve this answer | |

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.