【问题标题】:What is the maximum size of a Linux environment variable value?Linux 环境变量值的最大大小是多少?
【发布时间】:2010-11-07 20:39:26
【问题描述】:

Linux 环境变量中可以存储的数据量是否有限制,如果有:它是什么?

对于 Windows,我发现以下 KB article 总结为: Windows XP 或更高版本:8191 个字符 Windows 2000/NT 4.0:2047 个字符

【问题讨论】:

  • windows 上的实际限制是 31,767。您阅读了有关 set 命令的信息,该命令的命令行限制为 8191 个字符。 See this msdn article 不过仍然是随机限制。
  • 8191 并不是那么随机。它是 2^13 - 1。
  • AWS Lambda:[环境变量]集的总大小不超过 4 KB (source)
  • @BarnabyDawson 也许克里斯托弗的意思是因为它是任意的?

标签: linux shell environment-variables


【解决方案1】:

我认为 Linux 上没有每个环境变量的限制。所有环境变量放在一起的总大小限制在execve() 时间。有关详细信息,请参阅“参数和环境大小限制”here

一个进程可以使用setenv()putenv() 来扩展环境,使其超出 exec 分配的初始空间。

这是一个创建 256 MB 环境变量的快速而肮脏的程序。

#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;
}

【讨论】:

  • +1 获取 execve() 信息。您实际上可以将环境变量添加到(至少)8M,但 exec() 调用将不起作用。每当您尝试运行命令时,这在 bash 中表现为“参数列表太长”。
  • 另请注意,POSIX 要求 ARG_MAX 至少为 _POSIX_ARG_MAX,应为 4096。
  • The top answer (by Chipaca) on askUbuntu 讨论使用xargs --show-limits 获取更多信息。
  • 我也看到了每个 arg 字符串的限制 - “另外,每个字符串的限制是 32 页(内核常量 MAX_ARG_STRLEN)”
【解决方案2】:

嗯,我的盒子里至少有 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 中获取实际信息。如果它@ 开头,则它使用环境变量本身的值。


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

【讨论】:

  • 我希望你使用的是脚本,而不是手动输入!
  • 不,因此“变得无聊”。 Vi-mode 命令行编辑让它变得更容易一些,但我认为在达到 4M 标记之前它可能会失败。 C'est la vie。
  • @LưuVĩnhPhúc:因为程序有限制。它们可能是任意限制,也可能基于可用资源,但存在限制。很可能 DavidK 认为他的外壳不会(误)被应该知道得更好的疯子使用 :-)
【解决方案3】:

我使用以下 sn-p 在我的 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

所以:限制是相当高的!

【讨论】:

  • 18446744071562068096 字节约为 15 艾字节。 :) 这似乎是 512MiB 的一大飞跃。
  • @Marcus:它是......我想不知何故 1Gb 即 1073741824 字节即 2^30 字节在某处溢出。错误 18446744071562068096 中的字节数非常接近 2^64 即 18446744073709551616
  • 我的 C/gdb 技能有限,但我认为问题出在 bash 源文件 subst.c 函数 sub_append_string(第 726 行)使用名为 n 的有符号 int 变量来计算新大小。新尺寸 (2^31) 适合,但有对齐计算:n = (n + DEFAULT_ARRAY_SIZE) - (n % DEFAULT_ARRAY_SIZE);,我怀疑部分:(n + DEFAULT_ARRAY_SIZE) 溢出。一切都很好,但我们当然超出了这里的任何理智限制..
【解决方案4】:

这里有两个有用的命令:

  • getconf -a | grep ARG_MAX

  • true | xargs --show-limits

【讨论】:

  • 这 100 个变量中有哪些是相关的?它们记录在哪里?
  • @ingomueller.net:为了避免无用的结果,第一条命令可以限制为getconf -a | grep ARG_MAX
【解决方案5】:

不知道确切,但快速实验表明没有发生错误,例如具有 64kB 的值:

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

【讨论】:

    【解决方案6】:

    我使用了这个非常快速和肮脏的 php 代码(如下),针对不同的值对其进行了修改,发现它适用于高达 128k 的可变长度。之后,无论出于何种原因,它都不起作用;没有引发异常,没有报告错误,但该值没有显示在子shell中。

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

    不管怎样,默认情况下,在 CentOS 中,通过 php 中的 putenv 在环境中设置 var 的限制似乎在 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)
    

    【讨论】:

      【解决方案7】:

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

      【讨论】:

        【解决方案8】:

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

        在读取accessToken之前

        读取后-e accessToken

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

        【讨论】:

          猜你喜欢
          • 2017-03-23
          • 2021-12-01
          • 2019-05-19
          • 2016-01-13
          • 2011-02-28
          • 2012-07-18
          • 1970-01-01
          相关资源
          最近更新 更多