The rsync
utility can read pathnames from a file or an input stream. You may use find
to find the files you'd like to copy and then copy these with rsync
.
We will be assuming that you'd like to recursively search the directory /media/share/Books
for any regular file whose name matches the shell globbing pattern *.epub
. Any found file matching these criteria should be copied to the single directory /home/user/docker/calibre/books
without creating the corresponding directory structure found at the source hierarchy:
find /media/share/Books -type f -name '*.epub' -print0 |
rsync --from0 --files-from=- \
--archive --no-relative \
/ /home/user/docker/calibre/books
The way we're using find
above assumes that it supports the non-standard but commonly implemented -print0
predicate. If it does not, you may replace -print0
with -exec printf '%s\0' {} +
.
Note the options used with rsync
above. The --from0
option makes rsync
interpret the stream of data read with --files-from
as a nul-delimited list of pathnames. The -
used with --files-from
means "read from the standard input stream," i.e., from the find
command. We use the --archive
option (-a
) to copy/sync as much metadata as possible with each file and --no-relative
(--no-R
) to discard the directory path component of the read pathnames.
The source directory used with rsync
is /
since the pathnames that we read from find
are relative to the root directory.
This pipeline executes rsync
a single time and safely passes the pathnames between find
and rsync
. You only need to be aware that rsync
will resolve name collisions by simply ignoring other files with the same names as files already listed.
You could also call rsync
directly from find
using -exec
, but to make it a bit more efficient, we can use find
to find directories and then call rsync
to sync all the *.epub
files in each.
find /media/share/Books -type d -exec sh -c '
for dirpath do
rsync --archive \
--include="*.epub" --exclude="*" \
"$dirpath/" /home/user/docker/calibre/books
done' sh {} +
We're doing something similar here to what you tried but explicitly disallowing recursion by excluding directories from being processed. Instead of recursing with rsync
we are outsourcing that to find
.