How does 'find -exec' pass file names with spaces?
The find
command executes the command directly. The command, including the filename argument, will not be processed by the shell or anything else that might modify the filename. It's very safe.
You are correct that there's no need to escape filenames which are represented by {}
on the find
command line.
find
passes the raw filename from disk directly into the internal argument list of the -exec
command, in your case, the cp
command.
The question is two-part:
- how does
find
manage to call programs using-exec
without running into problems with spaces embedded in filenames, and - what good is the
-print0
option?
For the first, find
is making a system call, actually one of a group of related calls referred to as "exec". It passes the filename as an argument directly to this call, which then is passed directly (after creating a new process) without losing information about the filename.
The POSIX find
feature +
is explained as follows, in the rationale:
A feature of SVR4's
find
utility was the-exec
primary's + terminator. This allowed filenames containing special characters (especially newline characters) to be grouped together without the problems that occur if such filenames are piped toxargs
. Other implementations have added other ways to get around this problem, notably a-print0
primary that wrote filenames with a null byte terminator. This was considered here, but not adopted. Using a null terminator meant that any utility that was going to process find's-print0
output had to add a new option to parse the null terminators it would now be reading.
That "notably a -print0
primary" refers to GNU find
and xargs
which solve the problem in a different way. It is also supported by FreeBSD find
and xargs
. If you added a -0
option (see the manual page) to the xargs
call, then that program accepts lines terminated by "null byte" characters. In turn, xargs
calls exec-functions to do its work. The main distinction between the -print0
and -0
feature versus the +
feature is that the former passes the filenames over a pipe, while the latter does not. Developers find uses for almost any feature; the pipes are no exception.
Back to OP's example, which uses a -t
option to cp
: that is not found in POSIX cp. Rather, it is an extension (aka "nonstandard feature") provided by GNU cp. The -0
extension of xargs
would not improve this example, but there are other cases where it can be used effectively—keeping in mind that there is the portable alternative +
, which GNU find
accepts.