find 命令如何知道要使用“-exec ... {} +”提供多少个参数?

find 命令如何知道要使用“-exec ... {} +”提供多少个参数?

在这样的命令中:

find /data ! -type d -exec rm -f {} +

用于+批量执行rm -f.find应该批处理尽可能多的参数。但它怎么知道极限呢?

答案1

当调用withfind指定的命令时,对批处理参数的能力的限制通常由内核确定:它是赋予函数系列的参数的最大大小。 POSIX 定义了两种方法来发现与此相关的值,即参数的最大大小-exec+exec和环境给予一个exec电话

第一个是常量,因此在构建可执行文件时最终会“嵌入”可执行文件;它是常数ARG_MAXlimits.h

参数的最大长度执行功能包括环境数据。

其中第二个在运行时可用:它涉及使用功能sysconf,特别是_SC_ARG_MAX论证。

设置的限制ARG_MAX(适用于上述两种方法,因为它们都提供对“{ARG_MAX} 变量”的访问)是由 POSIX 指定, 关于-exec

任何两个或多个路径名集合的大小均应受到限制,以便实用程序的执行不会导致超出系统的 {ARG_MAX} 限制。

同样的道理xargs:

参数实用程序应限制命令行长度,以便在调用命令行时,组合的参数和环境列表(请参阅执行POSIX.1-2017 系统接口卷中的函数系列)不得超过 {ARG_MAX}-2048 字节。

各种实现以各种方式应用这些限制,有时应用比上述常量指示的值更小的值。例如,OpenBSDfind通过检查sysconf来确定最大命令行长度,同时也任意限制数字参数数量达到 5000;看源代码详细信息(感谢莫斯维供参考)。 GNUfind检查sysconf,并在必要时回退到ARG_MAX,或find指定的限制;此外,它还添加了指定的 2048 字节余量xargs(GNUfindxargs在此处分享其实现)。

特定的内核也可以添加自己的变化。什么定义了命令单个参数的最大大小?针对 Linux 讨论了这一点。由于不同的堆栈要求,Solaris 显然需要考虑不同的限制,具体取决于生成的进程(不是findxargs进程,而是未来的子进程)是 32 位还是 64 位;看libfind详细信息(感谢狡猾的对于指针)。赫德根本不限制参数

答案2

我最近在这里提到了一般规则:

makefile 的参数列表太长错误

这条规则的有效实施是我自己的libfindhttps://sourceforge.net/p/schillix-on/schillix-on/ci/default/tree/usr/src/lib/libfind/find.c#l2020

这里的主要问题是libfind需要知道当前环境大小以及正在调用的程序是 32 位程序还是 64 位程序,因为有不同的限制......

libfind之所以区分 32/64 位,是因为以前,当我在调用 32 位程序时从 64 位 shell 调用find -name '*.c' -exec count -t {} +获取较大项目的源代码行数时,我经常会遇到限制。libfindcount

Solarisfind实现不需要进行这种区分,因为 Solaris 不提供 64 位查找,因此使用 32 位限制至少在任何情况下都可以工作 - 即使它不使用最大可能的参数列表大小。

顺便说一句:因为findLinux 上的单个参数 (128k) 不太可能适用不必要的额外限制。这make是一个真正的问题,因为整个 shell 命令行都是作为单个参数传递的。另一方面,make不提前检查,因为make不包含分割长命令的代码。

PS:我刚刚发现了 Solaris 上的一个有趣的限制:两者都通过 from 调用它们的程序,并且如果xargs要调用的程序是不带 srcipt 的脚本,则实现会调用脚本的 shell 并使用固定的参数重新排序参数。大小数组。由于该数组只有 255 个条目,因此将 和的参数限制为 255,以防命令是一个如此简单的 shell 脚本。如果程序是这样的脚本并且 arglist 包含超过 255 个参数,则将返回.findexecvp()libc#!execvp()xargsfindexecvp()E2BIG

这里的问题是:您不能使用malloc()inside,execvp()因为execvp()可能是从通过 . 创建的进程中调用的vfork()。如果execvp()调用malloc(),这将导致父级中分配的内存无效...alloca()另一侧的调用总是成功,但可能会导致SIGSEGV超出本地堆栈大小的情况。

相关内容