The following command is working fine:
find . -iname \*.7z -exec ls {} -al \;But while I change \; to \+ , That is:
find . -iname \*.7z -exec ls {} -al \+I got error report:
missing argument to `-exec'I discover when I change {}'s position:
find . -iname \*.7z -exec ls -al {} \+The above command can work fine.
I feel confused about it.
1 Answer
The + form of -exec always places arguments at the end of the command you give. Therefore, {}, which represents the arguments, must immediately precede +. This is dissimilar to the ; form of -exec, which runs one command per file found and uses the filename wherever {} appears.
So that's your answer... but it does raise the additional question of why that limitation is in place in the first place, which is a bit murkier.
With +, the -exec action runs your command as few times as possible, passing as many filenames as it can in place of {}. Especially if there might be many files found, this form of -exec is only suitable for use with commands that behave the same--or at least in a way consistent with what you want--when the filenames are split across multiple invocations of the command, as they do when all the filenames appear in a single invocation.
Commands that accept a variable number of filename arguments in a single invocation, to produce the same effect as if the command were executed once for each filename, often accept them as trailing arguments. There are, of course, exceptions like cp and mv with directory targets (though you can pass -t dir to make those work with +). This is also somewhat easier to reason about, in that when you write ls -l followed by filenames, it feels like ls -l is "the command" you're running to operate on those named files, but when you write ls, followed by filenames, followed by -l, it doesn't quite feel that way.
As for what to do about it, your approach of simply putting options like -l before the {} is good. This has additional advantages: though less common on GNU/Linux systems like Ubuntu than on some other Unix-like operating systems, some commands don't accept options after a non-option argument has appeared. (See getopt(3) for details.)
Since you're running ls, you might consider using find's -ls action instead of -exec. Note also that you don't need to quote +, since unlike ;, shells don't treat the + character specially.