为什么for循环不会引发“参数过长”错误?


9

我发现这会引发“参数过长”错误:

ls *.*

这不会引起它:

for file in *.*
do
    echo $file
done

为什么?


您是否在两个实验中都使用了相同的外壳?也许/bin/bash/bin/sh(可能是短划线的链接)对决?
maxschlepzig 2011年

是的,我使用10000个文件名较长的文件进行了实验。“ ls *”失败,“ for for in in”成功。
lamwaiman1988'9

Answers:


13

如果参数的总大小(加上某些系统的环境)太大E2BIG,则execve系统调用会引发“参数过长”错误。该execve调用是启动外部进程的调用,特别是加载不同的可执行文件(存在另一个调用fork,用于运行代码仍来自同一可执行文件的单独进程)。该for循环是一个内部壳结构,所以它不涉及调用execve。该命令ls *.*不是在全局扩展时而是在ls调用时引发错误。

execveE2BIG当命令参数的总大小大于ARG_MAX 限制时,失败并显示错误。您可以使用以下命令在系统上查看此限制的值getconf ARG_MAX。(如果您有足够的内存,则有可能超过此限制;只要没有无关的错误发生,请ARG_MAX保证它execve可以工作。)


为什么外壳没有限制?
lamwaiman1988'9

1
@ gunbuster363 execve限制是由内核强制执行的,它设置了限制,因为参数需要在某一时刻通过内核内存复制,并且不允许用户进程请求任意数量的外壳内存。在外壳内部,没有任何限制,任何适合虚拟内存的都可以。
吉尔(Gilles)'所以

5

我想在第一个示例中lsbash通过fork/ execpair系统调用执行的,在第二个示例中,所有工作都是在内部进行的bash

exec调用有限制,内部工作bash,而不是有没有(或更好的,有什么都没有做不同的限制exec,也许可用内存量)。


你可以找到的限制,exec/usr/include/linux/limits.h通常情况下,被定义为ARG_MAX
2011年

如果我们使用shell进行循环,您是否认为大量项目会占用所有RAM?
lamwaiman1988'9

这个答案是不正确的。这不是“内部”,仅仅是参数和命令的限制不同。
多项式

5

因为在这种情况下ls它是一个参数,并且参数的数量是有限的。

for周期的情况下,这只是项目列表。(据我所知)没有任何限制。


外壳扩展绝对有限制。这与您有多少可用RAM密切相关。我的4GB RAM系统在大约1520万个8字节args参数上for i in {00000001..20000000} ;do ((10#$i==1)) && break; done

4
@fred我真的不认为需要提到RAM作为限制。
西蒙·托特

2
它可能不是必需的,但这是评论的性质。有人可能会觉得它有趣,甚至有价值。
Peter.O 2011年

@fred:实际上是的,如果扩展非常大的参数是一个常见问题,则可以在不将所有内容都保留在内存中的情况下实现它。
Matteo
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.