Using the following command, could someone please explain what exactly is the purpose for the ending curly braces ({}) and plus sign (+)?
And how would the command operate differently if they were excluded from the command?
find . -type d -exec chmod 775 {} +
Answers:
Thank you for visiting the Q&A section on Magenaut. Please note that all the answers may not help you solve the issue immediately. So please treat them as advisements. If you found the post helpful (or not), leave a comment & I’ll get back to you as soon as possible.
Method 1
The curly braces will be replaced by the results of the find command, and the chmod will be run on each of them. The + makes find attempt to run as few commands as possible (so, chmod 775 file1 file2 file3 as opposed to chmod 755 file1,chmod 755 file2,chmod 755 file3). Without them the command just gives an error. This is all explained in man find:
-exec command ;
Execute command; true if 0 status is returned.
All following
arguments tofindare taken to be arguments to the command until
an argument consisting of ‘;’ is encountered.
The string ‘{}’ is replaced by the current file name being processed everywhere
it occurs in the arguments to the command, not just in arguments
where it is alone, as in some versions offind. …
-exec command {} +
This variant of the
-execaction runs the specified command on
the selected files, but the command line is built by appending
each selected file name at the end; the total number of invocations of the command will be much less than the number of
matched files. …
Method 2
In addition to terdon’s answer,
- “Obviously”
-exec …must be terminated with either a semicolon (;)
or a plus sign (+). Semicolon is a special character in the shell
(or, at least, every shell I’ve ever used),
so, if it is to be used as part of thefindcommand,
it must be escaped or quoted (;,";", or';'). -
With
-exec … ;, the{}string may appear
any number of times in the command, including zero,
or two or more, in any position.
See this
for an example of why you might want to do-execwithout using{}.
Having two or more appearances is useful principally
because, in (at least) some versions offind,
the{}doesn’t need to be a word by itself;
it can have other characters at the beginning or end; e.g.,find . -type f -exec mv {} {}.bak ";"With
-exec … +,
the{}string must appear as the last argument before the+.
A command likefind . -name "*.bak" -exec mv {} backup_folder +results in the enigmatic
find: missing argument to ‘-exec’error message.-
A workaround for this that’s specific to the
cpandmvcommands isfind . -name "*.bak" -exec mv -t backup_folder {} +or
find . -name "*.bak" -exec mv --target-directory=backup_folder {} +
The
{}must be a word by itself;
it cannot have other characters at the beginning or end.
And, in (at least) some versions offind,
you may not have more than one{}. -
A workaround for this that’s specific to the
-
A sanity note: You can say
find . -name "*.sh" -type f -executable -exec {} optional args here ";"to run each of your scripts. But
find . -name "*.sh" -type f -executable -exec {} +runs one of your scripts, with the names of all the others as parameters.
This is similar to saying./*.sh
as a shell command,
exceptfinddoes not guarantee that it sorts its results,
so you aren’t guaranteed of runningaaa.sh
(your alphabetically first*.shfile)
as you would be with running./*.sh. -
An aspect of
findthat may not be perfectly clear to beginners is
that the command line is, effectively,
an executable statement in an arcane language.
For example,find . -name "*.sh" -type f -executable -print
means
for each file if the file’s name matches `*.sh` (i.e., if it ends with `.sh`) then if it is a plain file (i.e., not a directory) then if it is executable (i.e., the appropriate `---x--x--x` bit is set) then print the file’s name end if end if end if end loopor, simply,
for each file if the file’s name matches `*.sh` AND it is a plain file AND it is executable then print the file’s name end if end loopSome of the
-keywords are both an executable action and a test.
In particular, this is true for-exec … ;; for example,find . -type f -exec grep -q cat {} ";" -printtranslates to
for each file if it is a plain file (i.e., not a directory) then execute grep -q cat filename if the process succeeds (i.e., exits with status 0) then print the file’s name end if end if end loopwhich will print the names of all files containing the string “
cat”.
And, while this is something thatgrepcan do by itself
(with the-l(lower-caseL) option), it can be useful
to use it withfindto find files that contain a certain string
AND have a certain size AND are owned by a certain owner
AND were modified in a certain time range, ….However, this does not work for
-exec … +.
Since-exec … +executes one command for multiple files,
it doesn’t make sense to use it as a logical condition
inside afor each file …loop. - The flip side of the above is that
findgenerally exits
with an exit status of 0 unless you give it invalid arguments
or it encounters a directory that it can’t read.
Even if a program that you execute fails
(exits with a non-zero exit status),
findwill exit with an exit status of 0.
Except if a program that you execute with-exec … +fails
(exits with a non-zero exit status),
findwill exit with a non-zero exit status.
In addition to a million versions of find(1)
and testing what find actually does on a couple of systems,
The Open Group Base Specifications Issue 7, 2013 Edition
provided some of the information on what find must, may, and must not do.
All methods was sourced from stackoverflow.com or stackexchange.com, is licensed under cc by-sa 2.5, cc by-sa 3.0 and cc by-sa 4.0