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.