/usr/bin/printf
util 参数列表长度限制为 shell 的最大命令行长度(即, getconf ARG_MAX
在我的系统上为2097152);例子:
# try using a list that's way too long
/usr/bin/printf '%s\n' $(seq $(( $(getconf ARG_MAX) * 2 ))) | tail -1
输出:
bash: /usr/bin/printf: Argument list too long
今天我被告知shell builtin printf
没有这个限制。测试:
printf '%s\n' $(seq $(( $(getconf ARG_MAX) * 2 ))) | tail -1
输出:
4194304
问题:
略读
man bash dash
一下似乎并没有说明builtinprintf
的这种优势。它记录在哪里?builtin
printf
s ( eg )是否bash
有一个以字符为单位的参数列表最大长度,如果有,该长度是多少?
提倡使用任何特定实用程序并不是手册的真正职责。它应该主要描述可用的内置实用程序。
使用内置实用程序相对于外部实用程序的优势主要在于速度和扩展功能的可用性(例如
printf
,bash
可以使用 直接写入变量-v varname
,这是外部printf
无法做到的)。与执行内置实用程序相比,执行外部实用程序很慢,特别是如果经常在循环中执行,而且,正如您所注意到的,它们还允许更长的参数列表(这不是只有内置
printf
允许的,但所有内置实用程序)。内置
printf
实用程序的参数列表的长度受进程本身bash
的资源限制的限制。bash
在某些系统上,这甚至可能意味着您可以使用大部分可用 RAM 来构建其命令行参数列表。您可以从中找到这些不同信息的文档是
bash
源代码,您将在其中看到参数列表printf
是动态分配的链表,并且它不用于execve()
运行printf
(这是在运行外部实用程序时限制参数列表长度的原因)。一个没有
printf
内置实用程序的shell示例是OpenBSD 的 shell。该实用程序也可以在使用时禁用。ksh
bash
enable -n printf
这不是shell的限制,而是操作系统(Linux 内核)的限制,特别是其
execve(2)
系统调用的限制,并且是由命令行参数和环境变量传递给已启动程序的过时方式引起的。(请注意,该限制还包括环境变量!)。
由于 shell 内置程序没有通过
execve(2)
,因此它们不必有任何限制。现代 shell 通常不使用固定大小的缓冲区等,因此限制通常是由可用内存量和虚拟地址空间的布局强加的——即,对于所有意图和目的来说,它都是无限的。POSIX 标准要求在没有行限制的情况下实现 shell。
所以这是贝壳没有记录的自然现象。
顺便说一句:由于这个事实,shell 脚本可能不是文本文件,因为文本文件是行数不超过 LINE_MAX 的文件;-)