1

I want to get all the instances of a file in my macosx file system and copy them in a single folder of an external hard disk. I wrote a simple line of code in terminal but when I execute it, there is only a file in the target folder that is replaced at every occurrence it finds. It seems that the $RANDOM or $(uuidgen) used in a single command return only one value used for every occurrence {} of the find command. Is there a way to get a new value for every result of the find command? Thank you.

find . -iname test.txt -exec cp {} /Volumes/EXT/$(uuidgen) \;

or

find . -iname test.txt -exec cp {} /Volumes/EXT/$RANDOM \;
Cyrus
  • 84,225
  • 14
  • 89
  • 153

3 Answers3

2
find . -iname test.txt -exec bash -c '
    for i do
        cp "$i" "/Volumes/EXT/$RANDOM"
    done' _ {} +

You can use -exec with +, to pass multiple files to a bash loop. You can't use command subs (or multiple commands at all) in a single -exec.

dan
  • 4,846
  • 6
  • 15
2

This should work:

find ... -exec bash -c 'cp "$1" /Volumes/somewhere/$(uuidgen)' _ {} \;

Thanks to dan and pjh for corrections in comments.

Mark Setchell
  • 191,897
  • 31
  • 273
  • 432
  • 1
    should be: `find ... -exec bash -c 'cp "$1" /Volumes/somewhere/$(uuidgen)' _ {} \;` – dan Feb 20 '22 at 19:15
  • LGTM. Upvoted. I'm paranoid and would quote the second argument to `cp` to allow for weird values of `IFS`. – pjh Feb 20 '22 at 19:26
1

If you've got Bash 4.0 or later, another option is:

shopt -s dotglob
shopt -s globstar
shopt -s nocaseglob
shopt -s nullglob

for testfile in **/test.txt; do
    cp -- "$testfile" "/Volumes/EXT/$(uuidgen)"
done
  • shopt -s dotglob enables globs to match files and directories that begin with . (e.g. .dir/test.txt)
  • shopt -s globstar enables the use of ** to match paths recursively through directory trees
  • shopt -s nocaseglob causes globs to match in a case-insensitive fashion (like find option -iname versus -name)
  • shopt -s nullglob makes globs expand to nothing when nothing matches (otherwise they expand to the glob pattern itself, which is almost never useful in programs)
  • The -- in cp -- ... prevents paths that begin with hyphens (e.g. -dir/test.txt) being (mis)treated as options to `cp'
  • Note that this code might fail on versions of Bash prior to 4.3 because symlinks are (stupidly) followed while expanding ** patterns
pjh
  • 6,388
  • 2
  • 16
  • 17