如何导致“参数列表太长”错误?

Ser*_*nyy 14 command-line shell ulimit

问题的上下文:根据POSIX 规范, ARG_MAX 是函数系列的命令行参数的最大长度exec()。这让我相信这是实际的参数数量,但这显然不起作用:

$ ulimit -s
8192
$ touch {1..18000}.jpg
$ rm *.jpg
$ 
Run Code Online (Sandbox Code Playgroud)

显然,尽管长度超过 8192 个项目,但效果很好。根据DW 的回答8192应该以 kB 为单位的大小。很明显,之前的假设是错误的。

这是实际的问题进来:我如何找出项目的实际金额获得上述8192 KB的限制?换句话说,我必须执行什么样的计算才能确保这种*.jpg类型的 glob 会导致Argument list too long错误?

请注意,这不是What 定义单个命令参数的最大大小的副本。我知道getconf ARG_MAXulimit -s价值观,这不是我的问题。我需要知道如何生成大小超过 limit 的足够多的参数。换句话说,我需要找到一种方法来获取错误,而不是避免它。

Kus*_*nda 10

利用getconf ARG_MAX以产生一个长长的清单x,并要求与作为它的参数会产生“参数列表太长”错误的外部工具:

$ /bin/echo $( perl -e 'print "x" x $ARGV[0]' "$(getconf ARG_MAX)" )
/bin/sh: /bin/echo: Argument list too long
Run Code Online (Sandbox Code Playgroud)

环境和字符串的长度/bin/echo将包含在导致错误发生的原因中,因此我们可以尝试通过减去这些来找到最大可能的数字:

$ env
PATH=/usr/bin:/bin:/usr/sbin:/sbin:/usr/X11R6/bin:/usr/local/bin
Run Code Online (Sandbox Code Playgroud)

(我用 开始这个shell env -i sh,所以PATH环境中只有变量)

$ /bin/echo $( perl -e 'print "x" x ($ARGV[0] - length($ENV{"PATH"}) - length("/bin/echo"))' "$(getconf ARG_MAX)" )
sh: /bin/echo: Argument list too long
Run Code Online (Sandbox Code Playgroud)

还是太长了。到多少?

i=0
while ! /bin/echo $( perl -e 'print "x" x ($ARGV[0] - length($ENV{"PATH"}) - length("/bin/echo") - $ARGV[1])' "$(getconf ARG_MAX)" "$i" )
do
    i=$(( i + 1 ))
done
Run Code Online (Sandbox Code Playgroud)

此循环为 退出i=8

因此,有四个字节,我不能马上解释(八四个必须是名称的的PATH环境变量)。这些都为四根弦的空终结PATH,价值PATH/bin/echo和长串x字符。

请注意,每个参数都以空字符结尾,因此命令的参数越多,它们的组合长度就越短。


另外,只是为了展示一个大环境的效果:

$ export BIG=$( perl -e 'print "x" x $ARGV[0]' "$( getconf ARG_MAX )" )

$ /bin/echo hello
sh: /bin/echo: Argument list too long

$ /bin/echo
sh: /bin/echo: Argument list too long
Run Code Online (Sandbox Code Playgroud)

  • @dessert `ARG_MAX` 是环境和命令参数列表的组合长度的 _bytes_ 数,包括命令名称和每个参数(以及环境变量名称/值)上的任何空终止符。所以多字节字符会占用更多空间。它可能是内核或库缓冲区大小。 (2认同)
  • @Kusalananda,我知道这是参数字符串大小的限制,[在链接的问题中讨论](https://unix.stackexchange.com/a/120842/170373)。例如,这会触发它:`/bin/echo $( perl -e 'print "x" x $ARGV[0]' 131072 ) > /dev/null`(少一个)。我认为 `PATH_MAX` 通常是 4096(同样,在 Linux 上),我不认为它相关。 (2认同)

Ale*_*exP 8

在许多 Linux 发行版上,您可以通过运行来找出 ARG_MAX 的当前值

getconf ARG_MAX
Run Code Online (Sandbox Code Playgroud)

生成消息“参数列表太长”的一种简单方法是实际提供一个长参数列表;例如,在我的系统上

/bin/echo "$(find / -xdev 2> /dev/null)"
Run Code Online (Sandbox Code Playgroud)

有效,但是

/bin/echo "$(find / -xdev 2> /dev/null)" "$(find / -xdev 2> /dev/null)"
Run Code Online (Sandbox Code Playgroud)

产生

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

如需深入讨论,请参阅Stack Overflow 上的“ rm, cp, mv 命令的参数列表太长错误”。

PS 有问题的长度是存储参数和环境所需的实际内存量。它与参数的数量无关。


cat*_*cat 6

不是列出系统上的所有文件,这需要永远并且不适用于稀疏系统,命令

/bin/echo {1..200000}
Run Code Online (Sandbox Code Playgroud)

是一种更快(163 毫秒)的产生错误的方式。对我来说ARG_MAX2097152(2,097,152 大约 200 万)但命令仍然错误。

如果您的 shell 没有{start..end},您可以使用稍慢的(但仍然比列出文件快)

/bin/echo $(seq 1 200000)
Run Code Online (Sandbox Code Playgroud)

如果任一命令不起作用,只需增加最终值,直到它起作用,直到bash内存耗尽,或者直到seq无法计数为止。


ImH*_*ere 6

为了更轻松地启动一个新的 shell(exit完成后)并将限制设置为较低的值(100kbytes):

$ bash
$ ulimit -s 100
Run Code Online (Sandbox Code Playgroud)

对于您使用的示例,可能会触发错误:

$ touch {1..100000}.jpg
bash: /usr/bin/touch: Argument list too long
Run Code Online (Sandbox Code Playgroud)

但最好使用类似echo. 了解内置程序可能不会触发错误,此命令应该可以正常工作:

$ echo {000001..100000}6789
Run Code Online (Sandbox Code Playgroud)

另请注意,字节数远远超过上面设置的限制(1.1Mbyte):

$ echo {000001..100000}6789 | wc -c
1100000
Run Code Online (Sandbox Code Playgroud)

但是这个命令不起作用:

$ /bin/echo {000001..100000}6789
bash: /bin/echo: Argument list too long
Run Code Online (Sandbox Code Playgroud)

该限制由添加到 shell 环境大小的参数列表的大小(以字节为单位)设置。