Linux环境变量值的最大大小是多少?

119

在Linux上,环境变量中存储的数据量是否有限制?如果有,它是多少?

对于Windows,我找到了以下KB文章总结如下: Windows XP或更高版本:8191个字符 Windows 2000 / NT 4.0:2047个字符


3
Windows的实际限制是31,767。您可以了解到set命令,其命令行限制为8191个字符。请参阅此msdn文章尽管如此,这仍然是一个随机的限制。 - Christopher Currens
6
8191并不是那么随机,它等于2的13次方减1。 - Barnaby Dawson
1
AWS Lambda:环境变量集合的总大小不超过4 KB(来源) - Martin Thoma
1
@BarnabyDawson 或许 Christopher 的意思是它是任意的意思? - 0xC0000022L
8个回答

98

我认为Linux上没有针对每个环境变量的限制。所有环境变量的总大小在 execve() 运行时受到限制。请参阅这里的“关于参数和环境大小的限制”获取更多信息。

进程可以使用 setenv() 或者 putenv() 来扩展环境,超过原始空间的分配。

以下是一个快速并且简陋的程序,用于创建 256MB 的环境变量。

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>

int main(void)
{
  size_t size = 1 << 28; /* 256 MB */
  char *var;

  var = malloc(size);
  if (var == NULL) {
  perror("malloc");
  return 1;
}

  memset(var, 'X', size);
  var[size - 1] = '\0';
  var[0] = 'A';
  var[1] = '=';

  if (putenv(var) != 0) {
  perror("putenv");
  return 1;
}

  /*  Demonstrate E2BIG failure explained by paxdiablo */
  execl("/bin/true", "true", (char *)NULL);
  perror("execl");


  printf("A=%s\n", getenv("A"));

  return 0;
}

7
+1 对于 execve() 的信息。实际上,您可以添加环境变量多达(至少)8M,但是 exec() 调用将无法工作。当您尝试运行命令时,在 bash 中会表现为“参数列表太长”。 - paxdiablo
1
请注意,POSIX 要求 ARG_MAX 至少为 _POSIX_ARG_MAX,其值应为 4096。 - ninjalj
16
在askUbuntu上,最佳答案(由Chipaca提供)讨论了使用“xargs --show-limits”命令来获取更多信息。 - DocSalvager
1
我看到每个参数字符串的限制是 - "此外,每个字符串的限制为32页(内核常量MAX_ARG_STRLEN)"。 - kiran01bm

37

在我的电脑上,至少有4M。在那个时间点,我感到厌倦并离开了。希望终端输出会在我周一回到工作之前完成 :-)

export b1=A
export b2=$b1$b1
export b4=$b2$b2
export b8=$b4$b4
export b16=$b8$b8
export b32=$b16$b16
export b64=$b32$b32
export b128=$b64$b64
export b256=$b128$b128
export b512=$b256$b256
export b1k=$b512$b512
export b2k=$b1k$b1k
export b4k=$b2k$b2k
export b8k=$b4k$b4k
export b16k=$b8k$b8k
export b32k=$b16k$b16k
export b64k=$b32k$b32k
export b128k=$b64k$b64k
export b256k=$b128k$b128k
export b512k=$b256k$b256k
export b1m=$b512k$b512k
export b2m=$b1m$b1m
export b4m=$b2m$b2m
echo $b4m
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
:    :    :    :    :    :    :    :    :    :    :    :
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA

如果你担心4M的环境变量不足够,你可能需要重新考虑你的做法。

也许把信息放入文件,然后使用环境变量引用该文件会是一个更好的想法。我见过一些情况,如果变量的形式为@/path/to/any/fspec,它会从文件path/to/any/fspec中获取实际信息。如果它不是@开头,则使用环境变量本身的值。


有趣的是,即使设置了所有这些变量,每个命令都会开始抱怨参数列表太长了,所以,尽管允许你设置它们,但在完成后可能无法启动程序(因为必须将环境传递给这些程序)。


1
我希望你使用了脚本,而不是手动输入的! - Chris Huang-Leaver
2
不,这就是“感到无聊”的原因。Vi 模式的命令行编辑使它变得稍微容易一些,但我认为在达到 4M 的标记之前它可能会失败。这就是生活。 - paxdiablo
1
但是,为什么Ksh变量会在256K处停止呢?可能还涉及到CentOS。 - phuclv
@LưuVĩnhPhúc:因为程序有限制。它们可能是任意的限制,也可能基于可用资源,但这些限制是存在的。很可能DavidK假设他的shell不会被那些应该知道更好的疯子(误)使用 :-) - paxdiablo

20
以下是两个有用的命令:
  • getconf -a | grep ARG_MAX

  • true | xargs --show-limits

说明:上述命令均涉及Linux系统中的IT技术。

1
这应该是被接受的答案。这两个命令在 macOS Ventura 上也可以工作。 - Teddy C

9
我在我的Linux系统上使用以下代码片段进行了快速测试:
a="1"
while true
do
    a=$a$a
    echo "$(date) $(numfmt --to=iec-i --suffix=B --padding=7 ${#a})" 
done

在我的 Gentoo 3.17.8-gentoo-r1 系统上,这个命令的输出结果如下(最后几行):
Wed Jan  3 12:16:10 CET 2018   16MiB
Wed Jan  3 12:16:11 CET 2018   32MiB
Wed Jan  3 12:16:12 CET 2018   64MiB
Wed Jan  3 12:16:15 CET 2018  128MiB
Wed Jan  3 12:16:21 CET 2018  256MiB
Wed Jan  3 12:16:33 CET 2018  512MiB
xrealloc: cannot allocate 18446744071562068096 bytes

所以:限制非常高!

2
18446744071562068096字节约为15艾克斯字节。 :) 看起来跟512MiB相比是一个很大的飞跃。 - Marcus
2
@Marcus:我猜可能是1GB,即1073741824字节,即2^30字节在某个地方溢出了。错误代码18446744071562068096中的字节数非常接近2^64,即18446744073709551616。 - cyberbird
2
我对C/gdb的技能有限,但我认为问题在bash源文件subst.c中。函数sub_append_string(第726行)使用一个名为n的有符号整数变量来计算新大小。新大小(2^31)可以适合,但有一个对齐计算:n = (n + DEFAULT_ARRAY_SIZE) - (n % DEFAULT_ARRAY_SIZE); 我怀疑部分:(n + DEFAULT_ARRAY_SIZE) 溢出了。非常好,但我们当然远远超出了任何理智的限制... - cyberbird

1

不确定,但是快速实验表明,例如使用64kB的值不会出现错误:

% perl -e 'print "#include <stdlib.h>\nint main() { return setenv(\"FOO\", \"", "x"x65536, "\", 1); }\n";'\
| gcc -x c -o envtest - && ./envtest && echo $?
0

1

我使用了一个非常快速且不规范的PHP代码(如下),针对不同的值进行修改,并发现它适用于长度最多为128k的变量。在那之后,出于任何原因,它都不起作用;没有引发异常,也没有报告错误,但该值不会显示在子shell中。

也许这是PHP特定的限制?也许有php.ini设置可能会影响它?或者可能存在子shell将继承的变量大小限制?也许有相关的内核或shell配置设置...

无论如何, CentOS默认情况下,在PHP中通过putenv设置环境变量的限制似乎约为128k。

<?php

  $s = 'abcdefghijklmnop';
  $s2 = "";
  for ($i = 0; $i < 8100; $i++) $s2 .= $s;
  $result = putenv('FOO='.$s2);
  print shell_exec('echo \'FOO: \'${FOO}');
  print "length of s2: ".strlen($s2)."\n";
  print "result = $result\n";
?>

版本信息 -

[root@localhost scratch]# php --version
PHP 5.2.6 (cli) (built: Dec  2 2008 16:32:08) 
<..snip..>

[root@localhost scratch]# uname -a
Linux localhost.localdomain 2.6.18-128.2.1.el5 #1 SMP Tue Jul 14 06:36:37 EDT 2009 x86_64 x86_64 x86_64 GNU/Linux

[root@localhost scratch]# cat /etc/redhat-release 
CentOS release 5.3 (Final)

0

命令行(包括所有参数)加上环境变量应小于128k。


0

在我的情况下,这是由于使用read命令接受变量输入值时缓冲区被限制。解决方案是添加-e选项。

在读取accessToken之前:

在读取-e accessToken之后:

文档:http://linuxcommand.org/lc3_man_pages/readh.html


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接