I'm looking to copy files from subdirectories that match this pattern


into a folder


Sounds pretty easy:

cp vendor/plugin/*/tasks/*.rake lib/tasks

Or if the first * should match a whole subtree, use something like:

find vendor/plugin -path "*/tasks/*.rake" -exec cp "{}" lib/tasks +
  • You can't use -exec cp {} arg + that way. With +, {} has to be the last argument. So -exec sh -c 'exec cp "$@" lib/tasks' sh {} + Mar 20 '19 at 12:40
  • 1
    Note that with find, both * will match any number of subdirectories, so it would match on vendor/plugin/a/b/c/tasks/e/f/g/h.rake for instance. Mar 20 '19 at 12:42

Assuming you want to handle name collisions (for example, the collision that would occur between vendor/plugin/a/tasks/1.rake and vendor/plugin/b/tasks/1.rake) by being notified about them instead of overwriting files, then use a shell loop:


for pathname in vendor/plugin/*/tasks/*.rake

    if [ -e "$destpath" ]; then
        printf 'Can not move "%s", "%s" is in the way' \
            "$pathname" "$destpath" >&2

    cp "$pathname" "$destpath"

The line


could also be written as

destpath=$destdir/$(basename "$pathname")

and simply constructs the pathname for the destination for the sake of checking whether it's already taken.

You could also just do

cp -i vendor/plugin/*/tasks/*.rake lib/tasks

to get an interactive prompt for each name collision from the cp utility itself. The command relies on expanding the vendor/plugin/*/tasks/*.rake pattern on the command line, and depending on how many pathnames that expands to, it may potentially trigger a "argument list too long" error, in which case a loop may be used instead:

for pathname in vendor/plugin/*/tasks/*.rake
    cp -i "$pathname" lib/tasks

This loop is pretty much identical to the initial loop in this answer. The only difference is that we let the cp utility prompt the user whenever there is a name collision.

All variations above assume that the pattern vendor/plugin/*/tasks/*.rake actually matches something and that the destination directory lib/tasks already exists. I also assume that you are not interested in subdirectories or files with hidden names.

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.