What type of parameter/flag can I use with the Unix find
command so that I search executables?
Tip of the hat to @gniourf_gniourf for clearing up a fundamental misconception.
This answer attempts to provide an overview of the existing answers and to discuss their subtleties and relative merits as well as to provide background information, especially with respect to portability.
Finding files that are executable can refer to two distinct use cases:
Note that in either scenario it may make sense to use find -L ...
instead of just find ...
in order to also find symlinks to executables.
Note that the simplest file-centric case - looking for executables with the executable permissions bit set for ALL three security principals (user, group, other) - will typically, but not necessarily yield the same results as the user-centric scenario - and it's important to understand the difference.
-executable
)The accepted answer commendably recommends -executable
, IF GNU find
is available.
find
comes with most Linux distros
-executable
matches only files the current user can execute (there are edge cases.[1]).The BSD find
alternative offered by the accepted answer (-perm +111
) answers a different, file-centric question (as the answer itself states).
-perm
to answer the user-centric question is impossible, because what is needed is to relate the file's user and group identity to the current user's, whereas -perm
can only test the file's permissions.Thus, the best -perm
can do (by itself) is an approximation of -executable
. Perhaps a closer approximation than -perm +111
is -perm -111
, so as to find files that have the executable bit set for ALL security principals (user, group, other) - this strikes me as the typical real-world scenario. As a bonus, it also happens to be POSIX-compliant (use find -L
to include symlinks, see farther below for an explanation):
find . -type f -perm -111 # or: find . -type f -perm -a=x
gniourf_gniourf's answer provides a true, portable equivalent of -executable
, using -exec test -x {} \;
, albeit at the expense of performance.
Combining -exec test -x {} \;
with -perm +111
(i.e., files with at least one executable bit set) may help performance in that exec
needn't be invoked for every file (the following uses the POSIX-compliant equivalent of BSD find -perm +111
/ GNU find -perm /111
; see farther below for an explanation):
find . -type f \( -perm -u=x -o -perm -g=x -o -perm -o=x \) -exec test -x {} \; -print
-perm
)-perm
primary (known as a test in GNU find terminology).
-perm
allows you to test for any file permissions, not just executability.111
), whereas symbolic modes are strings (e.g., a=x
).u
(user), g
(group) and o
(other), or a
to refer to all three. Permissions are expressed as x
for executable, for instance, and assigned to principals using operators =
, +
and -
; for a full discussion, including of octal modes, see the POSIX spec for the chmod utility.find
:
-
(e.g., -ug=x
) means: match files that have all the permissions specified (but matching files may have additional permissions).755
) means: match files that have this full, exact set of permissions.+
/
[2]File-centric command examples
Note:
+
or /
.!
for NOT (GNU find and BSD find also allow -not
); note that \!
is used in the examples so as to protect !
from shell history expansions-a
for AND (GNU find and BSD find also allow -and
)-o
for OR (GNU find and BSD find also allow -or
)-
, the =
and +
operators can be used interchangeably
(e.g., -u=x
is equivalent to -u+x
- unless you apply -x
later, but there's no point in doing that).,
to join partial modes; AND logic is implied; e.g., -u=x,g=x
means that both the user and the group executable bit must be set.-perm
expression with the NOT primary, !
.-print
, or -perm
; also known as actions and tests in GNU find) are implicitly joined with -a
(logical AND), and that -o
and possibly parentheses (escaped as \(
and \)
for the shell) are needed to implement OR logic.find -L ...
instead of just find ...
is used in order to also match symlinks to executables
-L
instructs find to evaluate the targets of symlinks instead of the symlinks themselves; therefore, without -L
, -type f
would ignore symlinks altogether.# Match files that have ALL executable bits set - for ALL 3 security
# principals (u (user), g (group), o (others)) and are therefore executable
# by *anyone*.
# This is the typical case, and applies to executables in _system_ locations
# (e.g., /bin) and user-installed executables in _shared_ locations
# (e.g., /usr/local/bin), for instance.
find -L . -type f -perm -a=x # -a=x is the same as -ugo=x
# The POSIX-compliant equivalent of `-perm +111` from the accepted answer:
# Match files that have ANY executable bit set.
# Note the need to group the permission tests using parentheses.
find -L . -type f \( -perm -u=x -o -perm -g=x -o -perm -o=x \)
# A somewhat contrived example to demonstrate the use of a multi-principial
# mode (comma-separated clauses) and negation:
# Match files that have _both_ the user and group executable bit set, while
# also _not_ having the other executable bit set.
find -L . -type f -perm -u=x,g=x \! -perm -o=x
[1] Description of -executable
from man find
as of GNU find 4.4.2:
Matches files which are executable and directories which are searchable (in a file name resolution sense). This takes into account access control lists and other permissions artefacts which the -perm test ignores. This test makes use of the access(2) system call, and so can be fooled by NFS servers which do UID mapping (or root-squashing), since many systems implement access(2) in the client's kernel and so cannot make use of the UID mapping information held on the server. Because this test is based only on the result of the access(2) system call, there is no guarantee that a file for which this test succeeds can actually be executed.
[2] GNU find versions older than 4.5.12 also allowed prefix +
, but this was first deprecated and eventually removed, because combining +
with symbolic modes yields likely yields unexpected results due to being interpreted as an exact permissions mask. If you (a) run on a version before 4.5.12 and (b) restrict yourself to octal modes only, you could get away with using +
with both GNU find and BSD find, but it's not a good idea.