Shell内置`printf`行限制?

agc*_*agc 6 shell bash dash shell-builtin printf

/usr/bin/printfUTIL参数列表的长度被限制在外壳的最大命令行长度( 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
Run Code Online (Sandbox Code Playgroud)

输出:

bash: /usr/bin/printf: Argument list too long
Run Code Online (Sandbox Code Playgroud)

今天我被告知shell内置 printf没有这个限制;测试:

printf '%s\n' $(seq $(( $(getconf ARG_MAX) * 2 ))) | tail -1
Run Code Online (Sandbox Code Playgroud)

输出:

4194304
Run Code Online (Sandbox Code Playgroud)

问题:

  1. 略读man bash dash一下似乎并没有说明builtin 的 这种优势printf。凡它记录?

  2. 难道内置 printfS(例如 bash)在字符的参数列表最大长度,如果是这样,那是什么长度?

Kus*_*nda 14

提倡使用任何特定实用程序并不是手册的真正职责。它应该主要描述可用的内置实用程序。

使用内置实用程序比使用外部实用程序的优势主要是速度和扩展功能的可用性(例如,printfinbash可以直接写入带有 的变量-v varname,这是外部printf无法做到的)。

与执行内置实用程序相比,执行外部实用程序很慢,特别是如果经常在循环中执行,并且正如您所注意到的,它们还允许更长的参数列表(这不是只有内置程序才printf允许的) ,但所有内置实用程序)。

内置printf实用程序的参数列表的长度bashbash进程本身的资源限制。在某些系统上,这甚至可能意味着您可以使用大部分可用 RAM 来构建其命令行参数列表。

您可以从中找到这些各种信息的文档是

  • bash源代码,在那里你会看到,参数列表printf是一个动态分配的链接列表,并认为它使用execve()运行printf(这是运行外部工具时,有什么限制参数列表的长度)。

外壳的例子,其中printf没有内置的实用工具是kshOpenBSD的壳。也可以在使用时禁用该实用程序。bashenable -n printf

  • @SergiyKolodyazhnyy,它内置于 `ksh93` 中。它不在 ksh88、pdksh 和它的一些衍生版本中,例如 OpenBSD ksh 或 mksh 的一些构建版本。如果不是特别是在 ksh 中,`echo` 通常不可靠,这很烦人。 (2认同)

小智 2

/usr/bin/printf util 参数列表长度限制为 shell 的最大命令行长度(即 getconf ARG_MAX,在我的系统上为 2097152);例子:

这不是shell的限制,而是操作系统(Linux 内核)的限制,特别是其execve(2)系统调用的限制,并且是由命令行参数和环境变量传递到启动程序的过时方式引起的。

(请注意,该限制还包括环境变量!)。

man bash dash 的浏览似乎并没有说明内置 printf 的这一优势。它记录在哪里?内置 printfs 是否有参数列表长度(例如 bash),如果有,它是什么?

由于 shell 内置函数不会通过,因此execve(2)它们不必有任何这样的限制。现代 shell 通常不使用固定大小的缓冲区等,因此限制通常是由可用内存量和虚拟地址空间的布局所施加的——即,它对于所有意图和目的都是无限的。

  • “无限制”意味着您的程序在达到该限制之前将中断或崩溃。但是,如果您的计算机+操作系统使用虚拟内存,则您的进程可以使用大于物理内存和交换的字符串或任何数据结构。大文件可以在进程的地址空间中映射,并显示为一大块内存,但其数据不必同时全部分页。 (2认同)