To complement Jonathan Leffler's helpful answer and @muru's helfpul comments:
The last command command in your question should work in terms of precedence:
find implicitly combines tests such as -type and actions such as -print with -and (logical AND; the POSIX-compliant form is -a ).
- By contrast,
-maxdepth is an option, which is not positional and always applies to the whole command.
- For an overview of
find terminology and concepts, see this answer of mine.
- Your last solution attempt correctly uses parentheses to change the implied evaluation precedence to achieve the desired logic (
-or has lower precedence than -and).
- By contrast, the parentheses in your first solution attempt,
-or \( -type l \), have no effect on precedence at all, because they enclose a single test only (whereas precedence by definition only matters for multiple operands).
- Note how
( and ) are quoted as \( and \) to protect them from interpretation by the shell; '(' and ')' would work too.
However, the -perm test likely does NOT do what you want it to: as written, it tests symlinks themselves for being executable, as opposed to their target. Given that symlinks are always marked as executable, irrespective of whether their target is, you'll end up matching any symlink, even if it doesn't refer to an executable file.
- To fix that, use the
-L option, which makes find apply tests such as -perm to the target of a symlink.
- Note, however, that there's a side effect: with
-L, when find encounters a symlink to a directory, it descends into that directory (i.e., it processes the symlink's target directory as well), which by default does not happen.
With the above in mind, somewhat ironically, the need for parentheses goes away altogether, because \( -type f -or -type l \) can be replaced with just -type f, given that -L now ensures that a symlink target's type is tested:
Note:
- I've removed the {} from the following commands to focus on the find command only. Without a filename argument, GNU find implicitly operates on the current directory (. is implied); BSD find, by contrast requires a filename argument.
- Also, /111 rather than +111 is used as the permissions mask, because the + syntax was deprecated a while ago and was actually removed in GNU find 4.5.12.
- Finally, -maxdepth 1 was placed before the first positional element (test -name) not only for greater conceptual clarity (as stated -maxdepth, because it is an option, always applies to the entire command), but also to suppress a warning that recent versions of GNU find would otherwise issue.
find -L -maxdepth 1 -name 'upvoter-*' -type f -perm /111
Additional thoughts about your command:
-perm /111 (-perm +111) applies any-specified-bit-set logic i.e., it tests whether the executable bit is set for any security principal; the symbolic-mode equivalent is -perm /a=x.
- As stated, the
+ syntax was deprecated a while ago and removed in GNU find v4.5.12.
- BSD
find, by contrast, continues to only support +, which unfortunately means that no single command with this feature will work with both implementations with GNU find 4.5.12 or higher.
- In any event, this feature is nonstandard (not POSIX-compliant).
- If instead you wanted to match only files where all execution bits are set, use prefix
-: -perm -111 or -perm -a=x
- Alternatively, if you wanted to test whether files are executable by you, use the
-executable test (a GNU find extension).
- Also,
-executable "takes into account access control lists and other permissions artefacts which the -perm test ignores." (from man find).
Finally, GNU xargs's -i option is deprecated; the manual recommends using -I {} instead.