命令行长度限制:内置与可执行文件

命令行长度限制:内置与可执行文件

所以按照POSIX规范我们有以下定义*

扩展到位置参数,从 1 开始,最初为设置的每个位置参数生成一个字段。当扩展发生在将执行字段拆分的上下文中时,任何空字段都可能被丢弃,并且每个非空字段应进一步拆分,如字段拆分中所述。当扩展发生在不执行字段拆分的上下文中时,如果 IFS 包含至少一个字符,则初始字段应连接以形成单个字段,每个参数的值由 IFS 变量的第一个字符分隔,或者如果未设置 IFS,则用 a 分隔;如果 IFS 设置为空字符串,则不使用分隔符。

对于绝大多数人来说,我们都知道一个著名的ARG_MAX限制:

$ getconf ARG_MAX
2621440

这可能会导致:

$ cat * | sort -u > /tmp/bla.txt
-bash: /bin/cat: Argument list too long

值得庆幸的是,背后的好人bash([包括所有类似 POSIX 的其他人])为我们提供了printf内置功能,因此我们可以简单地:

printf '%s\0' * | sort -u --files0-from=- > /tmp/bla.txt

一切对用户来说都是透明的。

有人可以告诉我为什么ARG_MAX使用built-in命令绕过限制是如此简单,以及为什么提供一个一致的 POSIX shell 解释器来优雅地处理*独立可执行文件的特殊参数是如此困难:

$ cat *

那会破坏什么东西吗?我并不是要求bash人们提供cat内置命令,我只对操作顺序感兴趣,以及为什么*根据命令是内置命令还是独立可执行文件以不同的行为进行扩展。

答案1

限制不在于 shell,而在于exec()函数系列。

POSIX 标准与此相关的说法

新进程的组合参数和环境列表可用的字节数为{ARG_MAX}。空终止符、指针和/或任何对齐字节是否包含在该总数中是由实现定义的。

要运行 shell 中内置的实用程序,shell 不需要调用exec(),因此它不受此限制的影响。

另请注意,受限制的不仅仅是命令行的长度,还包括命令长度、其参数以及当前环境变量及其值的组合。

还要注意的printf不是pdksh例如(它恰好充当shOpenBSD上的)内置实用程序ksh。依赖它作为内置程序需要考虑正在使用的特定 shell。

答案2

善行难陀回答解释了为什么ARG_MAXshell 内置程序没有问题。

就以cat *不受 影响的方式实现而言ARG_MAX,这样做是微不足道的:cat实现所需要做的就是使用glob(3)来实现它自己的通配符,然后您可以使用cat \*或运行它cat '*',这样 shell 就不会执行自己的通配符。您会发现 Linux 或 Unix 风格的系统上有一些命令可以处理它们自己的通配符,至少在某些情况下是这样;许多具有本机 DOS 版本的命令至少会包含处理通配符的代码,因为那里的 shell 本身不会通配符外部命令的find参数tarzip

考虑到 POSIX shell 的期望,该功能将相当令人惊讶且难以发现!在早期的 Unix 版本中,通配符是使用单独的程序/etc/glob.

相关内容