使用 find 命令搜索可执行文件

我可以用 Unix find命令使用什么类型的参数/标志来搜索可执行文件?

156633 次浏览

你可以使用 -executable测试标志:

-executable
Matches files which are executable  and  directories  which  are
searchable  (in  a file name resolution sense).

在发现的 GNU 版本中,你可以使用 -executable:

find . -type f -executable -print

对于 BSD 版本的 find,可以使用 -perm+以及八进制掩码:

find . -type f -perm +111 -print

在这个上下文中,“ +”表示“设置了这些位中的任何一个”,111表示执行位。

注意,这与 GNUfind 中的 -executable谓词不完全相同。特别是,-executable测试文件是否可以由当前用户执行,而 -perm +111只测试是否设置了任何执行权限。

旧版本的 GNU find 也支持 -perm +111语法,但是从 4.5.12开始不再支持这种语法。相反,您可以使用 -perm /111来获得这种行为。

这对我很有用,我想分享..。

find ./ -type f -name "*" -not -name "*.o" -exec sh -c '
case "$(head -n 1 "$1")" in
?ELF*) exit 0;;
MZ*) exit 0;;
#!*/ocamlrun*)exit0;;
esac
exit 1
' sh {} \; -print

因此,为了有另一种可能性 1找到可执行的文件的当前用户:

find . -type f -exec test -x {} \; -print

(这里的 test 命令是 PATH 中的命令,很可能是 /usr/bin/test,而不是内置命令)。


1 只有在 find-executable标志不可用时才使用此选项!这与 -perm +111解决方案有微妙的不同。

这是如此的 荒谬,这是不是超级容易... 更不用说 几乎不可能。举起手来,我尊重苹果/聚光灯..。

mdfind 'kMDItemContentType=public.unix-executable'

至少它起作用了!

向@(咒语)致敬,以澄清一个根本性的误解。

这个答案试图提供一个 现有答案概览,讨论它们的 微妙之处相对优点,以及提供 背景资料,特别是关于 便携性

查找可执行文件可以参考 两个不同的用例:

  • 以用户为中心 : 查找 当前用户的可执行文件 < em > 文件。
  • 以文件为中心 : 查找具有(一个或多个) < em > 可执行权限 bit set的文件。

请注意,在 都不是场景中,它可能对 使用 find -L ...有意义,而不仅仅是 find ...,以便 还可以找到 < em > 到 可执行文件的符号链接

请注意,最简单的以文件为中心的情况-寻找可执行文件的可执行权限位设置为 ALL 三个安全主体(用户,组,其他)-将 一般来说,但 不一定产生相同的结果作为以用户为中心的情况-这是很重要的了解差异。

以用户为中心(-executable)

  • 接受的答案值得推荐 -executable,IF GNU find是可用的。

    • GNU find提供了大多数 Linux发行版
      • 相比之下,包括 macOS 在内的基于 BSD 的平台都带有 BSD find,它的功能不那么强大。
    • 根据场景的要求,-executable只匹配 当前用户可以执行的文件(有边缘案例 [1])。
  • < em > BSD 由认可答案提供的 ABC0选择(-perm +111) 回答 a < em > 不同 ,< em > file -中心问题(正如答案本身所述)。

    • 仅使用 -perm来回答以 使用者为中心的问题是 不可能 ,因为需要的是 联系起来文件用户和 当前用户的的组标识,而 -perm只能测试 文件的权限。
      只使用 POSIX find特性,如果不涉及外部实用程序,就无法回答这个问题。
    • 因此,-executable最好的 -perm(自己)是 < em > 近似 也许一个比 ABC2更接近的近似值是 -perm -111,以便找到为所有安全主体(用户,组,其他)设置了可执行位的文件-这是典型的现实场景。作为一个额外的好处,它也是 POSIX 兼容的(使用 find -L包含符号链接,参见下面的解释) :

      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
      

File-centric (-perm)

  • To answer file-centric questions, it is sufficient to use the POSIX-compliant -perm primary (known as a test in GNU find terminology).
    • -perm allows you to test for any file permissions, not just executability.
    • Permissions are specified as either octal or symbolic modes. Octal modes are octal numbers (e.g., 111), whereas symbolic modes are strings (e.g., a=x).
    • Symbolic modes identify the security principals as 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.
    • In the context of find:
      • Prefixing a mode with - (e.g., -ug=x) means: match files that have all the permissions specified (but matching files may have additional permissions).
      • Having NO prefix (e.g. 755) means: match files that have this full, exact set of permissions.
      • Caveat: Both GNU find and BSD find implement an additional, nonstandard prefix with are-ANY-of-the-specified-permission-bits-set logic, but do so with incompatible syntax:
        • BSD find: +
        • GNU find: / [2]
      • Therefore, avoid these extensions, if your code must be portable.
  • The examples below demonstrate portable answers to various file-centric questions.

File-centric command examples

Note:

  • The following examples are POSIX-compliant, meaning they should work in any POSIX-compatible implementation, including GNU find and BSD find; specifically, this requires:
    • NOT using nonstandard mode prefixes + or /.
    • Using the POSIX forms of the logical-operator primaries:
      • ! 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 examples use symbolic modes, because they're easier to read and remember.
    • With mode prefix -, 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).
    • Use , 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.
    • Modes cannot themselves express negative matching in the sense of "match only if this bit is NOT set"; you must use a separate -perm expression with the NOT primary, !.
  • Note that find's primaries (such as -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]从 man find到 GNU 对 -executable的描述 find 4.4.2:

匹配可执行文件和可搜索目录(在文件名解析意义上)。这考虑到了访问权限 控件列表和 -perm 测试忽略的其他权限构件。这个测试使用 access (2)系统调用,因此可以 由于许多系统在客户机的内核中实现了访问(2) ,所以不能被进行 UID 映射(或根压缩)的 NFS 服务器愚弄 利用服务器上保存的 UID 映射信息。由于此测试仅基于 access (2)系统调用的结果,因此 并不能保证此测试成功的文件能够实际执行。

[2] GNU find 版本的 年龄超过4.5岁12也允许使用前缀 +,但是这个前缀最初被弃用并最终被删除,因为将 +象征性的模式结合起来可能会产生意想不到的结果,因为它被解释为 一模一样权限掩码。如果你(a)运行在一个版本 之前4.5.12 还有(b)限制自己只使用 八进制模式,你 +0逃脱使用 ++1 GNU 发现和 BSD 发现,但它不是一个好主意。

find . -executable -type f

并不能真正保证文件是可执行的,它会找到设置了执行位的文件。如果你愿意的话

chmod a+x image.jpg

上面的 find 将认为 image. jpg 是一个可执行文件,即使它实际上是一个设置了执行位的 jpeg 图像。

我通常是这样解决这个问题的:

find . -type f -executable -exec file {} \; | grep -wE "executable|shared object|ELF|script|a\.out|ASCII text"

如果你想让 find 打印出有关可执行文件的穹顶信息,你可以这样做:

find . -type f -executable -printf "%i.%D %s %m %U %G %C@ %p" 2>/dev/null |while read LINE
do
NAME=$(awk '{print $NF}' <<< $LINE)
file -b $NAME |grep -qEw "executable|shared object|ELF|script|a\.out|ASCII text" && echo $LINE
done

在上面的示例中,文件的完整路径名位于最后一个字段中,必须用 awk“ NAME = $(awk’{ print $NF }’< < $LINE)”反映查找它的位置 如果文件名在 find 输出字符串的其他位置,则需要用正确的数字位置替换“ NF”。如果你的分隔符不是空格,你也需要告诉 awk 你的分隔符是什么。

简单的答案是: “您的可执行文件位于 PATH 变量中包含的目录中”,但这并不能真正找到您的可执行文件,而且可能会错过很多可执行文件。

我对 mac 了解不多,但我认为“ mdfind‘ kMDItemContentType = public.unix-Executive’”可能会漏掉解释脚本之类的东西

如果您可以找到设置了可执行位的文件(不管它们是否实际上是可执行的) ,那么就可以这样做

find . -type f -perm +111 -print

其中支持“-Executive”选项,该选项将对 acl 和其他权限构件进行进一步筛选,但在技术上与“-pemr + 111”没有太大区别。

也许在将来 find 会支持“-magic”,并且允许您显式地查找具有特定 magic id 的文件... ... 但是之后您必须指定所有可执行格式 magic id。

我不知道 Unix 上有一个技术上正确的简单方法。

我遇到了同样的问题,答案就在 Dmenu 源代码中: 为此目的制作的 stest 实用程序。您可以编译‘ stest.c’和‘ arg.h’文件,它应该可以工作。这里有一个用法手册,我放在那里是为了方便:

STEST(1)         General Commands Manual         STEST(1)


NAME
stest - filter a list of files by properties


SYNOPSIS
stest  [-abcdefghlpqrsuwx]  [-n  file]  [-o  file]
[file...]


DESCRIPTION
stest takes a list of files  and  filters  by  the
files'  properties,  analogous  to test(1).  Files
which pass all tests are printed to stdout. If  no
files are given, stest reads files from stdin.


OPTIONS
-a     Test hidden files.


-b     Test that files are block specials.


-c     Test that files are character specials.


-d     Test that files are directories.


-e     Test that files exist.


-f     Test that files are regular files.


-g     Test  that  files  have  their set-group-ID
flag set.


-h     Test that files are symbolic links.


-l     Test the contents of a directory  given  as
an argument.


-n file
Test that files are newer than file.


-o file
Test that files are older than file.


-p     Test that files are named pipes.


-q     No  files are printed, only the exit status
is returned.


-r     Test that files are readable.


-s     Test that files are not empty.


-u     Test that files have their set-user-ID flag
set.


-v     Invert  the  sense  of  tests, only failing
files pass.


-w     Test that files are writable.


-x     Test that files are executable.


EXIT STATUS
0      At least one file passed all tests.


1      No files passed all tests.


2      An error occurred.


SEE ALSO
dmenu(1), test(1)


dmenu-4.6                STEST(1)

所以如果你真的想找到可执行的文件类型(例如脚本,ELF 二进制文件等等) ..。等)不仅仅是执行 abc 0的文件,那么你可能想做一些更像这样的事情(其中的工作目录。可以替换为您想要的任何目录) :

 gfind . -type f -exec bash -c '[[ $(file -b "'{}'") == *" executable "* ]] ' \; -print

或者对于那些不使用 macports (linux 用户)或者安装了 gnu find 作为 find 的用户:

 find . -type f -exec bash -c '[[ $(file -b "'{}'") == *" executable "* ]] ' \; -print

不过如果你在 OS X 上,它会附带一个叫做 is _ exec 的小实用程序,基本上可以把这个小测试捆绑起来,这样你就可以在找到它的时候缩短命令行。但是这种方法更加灵活,因为您可以轻松地将 = = 测试替换为 = ~ 测试,并使用它来检查更复杂的属性,比如可执行的纯文本文件或 file 命令返回的任何其他信息。


这里引用的确切规则是相当不透明的,所以我只是通过试验和错误来解决它,但我想听到正确的解释。