117

Is there a limit to the amount of data that can be stored in an environment variable on Linux, and if so: what is it?

For Windows, I've found following KB article which summarizes to: Windows XP or later: 8191 characters Windows 2000/NT 4.0: 2047 characters

gunr2171
  • 16,104
  • 25
  • 61
  • 88
Gio
  • 1,812
  • 2
  • 15
  • 15
  • 3
    The actual limit on windows is 31,767. You read about the `set` command, which has it's commandline limit to 8191 characters. [See this msdn article](http://msdn.microsoft.com/en-us/library/ms682653.aspx) Still a random limitation, though. – Christopher Currens Jan 29 '12 at 23:50
  • 6
    8191 isn't that random. It's 2^13 - 1. – Barnaby Dawson Mar 09 '17 at 11:21
  • 1
    AWS Lambda: the total size of the set [of environment variables] does not exceed 4 KB ([source](https://docs.aws.amazon.com/lambda/latest/dg/env_variables.html)) – Martin Thoma May 27 '19 at 09:17
  • 1
    @BarnabyDawson perhaps Christopher meant it in the sense that it was arbitrary? – 0xC0000022L Jun 04 '19 at 13:46

8 Answers8

98

I don't think there is a per-environment variable limit on Linux. The total size of all the environment variables put together is limited at execve() time. See "Limits on size of arguments and environment" here for more information.

A process may use setenv() or putenv() to grow the environment beyond the initial space allocated by exec.

Here's a quick and dirty program that creates a 256 MB environment variable.

#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;
}
Bonifacio2
  • 3,405
  • 6
  • 34
  • 54
sigjuice
  • 28,661
  • 12
  • 68
  • 93
  • 7
    +1 for the execve() info. You can actually add environment variables up to (at least) 8M but exec() calls will not work. This manifests itself in bash as "argument list is too long" whenever you then try to run a command. – paxdiablo Jul 06 '09 at 02:07
  • 1
    Also note that POSIX requires ARG_MAX to be at least _POSIX_ARG_MAX, which should be 4096. – ninjalj Aug 05 '10 at 21:09
  • 15
    [The top answer (by Chipaca) on askUbuntu](http://askubuntu.com/questions/14081/what-is-the-maximum-length-of-command-line-arguments-in-gnome-terminal) discusses using `xargs --show-limits` to get more info. – DocSalvager Jul 21 '13 at 06:46
  • 1
    I see limit per arg string too - "Additionally, the limit per string is 32 pages (the kernel constant MAX_ARG_STRLEN)" – kiran01bm Dec 16 '19 at 05:36
34

Well, it's at least 4M on my box. At that point, I got bored and wandered off. Hopefully the terminal output will be finished before I'm back at work on Monday :-)

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

If you're worried that 4M may not be enough for your environment variable, you may want to rethink how you're doing things.

Perhaps it would be a better idea to put the information into a file and then use an environment variable to reference that file. I've seen cases where, if the variable is of the form @/path/to/any/fspec, it gets the actual information from the file path/to/any/fspec. If it doesn't begin with @, it uses the value of the environment variable itself.


Interestingly enough, with all those variables set, every single command starts complaining that the argument list is too long so, even though it lets you set them, it may not be able to start programs after you've done it (since it has to pass the environment to those programs).

paxdiablo
  • 854,327
  • 234
  • 1,573
  • 1,953
  • 1
    I hope you used a script, and didn't type this all out by hand! – Chris Huang-Leaver Jul 03 '09 at 08:26
  • 2
    No, hence the "getting bored" bit. Vi-mode command line editing made it a little easier but I thought it might fail before I hit the 4M mark. C'est la vie. – paxdiablo Jul 03 '09 at 09:13
  • 1
    but [why do ksh variables stop at 256K](http://stackoverflow.com/q/14371326/995714)? Possibly [CentOS](http://stackoverflow.com/a/3419085/995714) too – phuclv Nov 24 '16 at 10:35
  • @LưuVĩnhPhúc: because programs have limits. They may be arbitrary limits or they may be based on available resources, but the limits exist. Quite possibly DavidK assumed his shell wouldn't be (mis-)used by lunatics who should know better :-) – paxdiablo Nov 24 '16 at 12:53
19

Here are two helpful commands:

  • getconf -a | grep ARG_MAX

  • true | xargs --show-limits

9

I did a quick test on my Linux box with the following snippet:

a="1"
while true
do
    a=$a$a
    echo "$(date) $(numfmt --to=iec-i --suffix=B --padding=7 ${#a})" 
done

On my box (Gentoo 3.17.8-gentoo-r1) this results in (last lines of output):

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

So: the limit is quite high!

cyberbird
  • 111
  • 1
  • 3
  • 2
    18446744071562068096 bytes is about 15 exabytes. :) That seems like a big jump from 512MiB. – Marcus May 16 '19 at 21:47
  • 2
    @Marcus: it is... I guess that somehow 1Gb i.e. 1073741824 bytes i.e. 2^30 bytes overflows somewhere. The number of bytes in the error 18446744071562068096 is pretty close to 2^64 i.e. 18446744073709551616 – cyberbird Feb 07 '20 at 16:29
  • 2
    I do have limited C/gdb skills but I think the issue is in the bash source file subst.c The function sub_append_string (line 726) uses a signed int variable called n to calculate the new size. The new size (2^31) would fit but there is an alignment calculation: `n = (n + DEFAULT_ARRAY_SIZE) - (n % DEFAULT_ARRAY_SIZE);` and I suspect the part: `(n + DEFAULT_ARRAY_SIZE)` overflows. All very nice but we are ofcourse way beyond any sane limit here.. – cyberbird Feb 09 '20 at 12:47
1

Don't know exactly but a quick experiment shows that no error occurs e.g. with 64kB of value:

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

I used this very quick and dirty php code (below), modifying it for different values, and found that it works for variable lengths up to 128k. After that, for whatever reason, it doesn't work; no exception is raised, no error is reported, but the value does not show up in the subshell.

Maybe this is a php-specific limit? Maybe there are php.ini settings that might affect it? Or maybe there's a limit on the size of vars that a subshell will inherit? Maybe there are relevant kernel or shell config settings..

Anyway, by default, in CentOS, the limit for setting a var in the environment via putenv in php seems to be about 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";
?>

Version info -

[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)
Shavais
  • 2,476
  • 1
  • 27
  • 25
0

The command line (with all argument) plus the environment variable should be less then 128k.

J-16 SDiZ
  • 26,473
  • 4
  • 65
  • 84
0

In my case it was due to buffer was limited when accepting a variable input value with read command. Solution was to add -e

Before read accessToken

After read -e accessToken

Docs: http://linuxcommand.org/lc3_man_pages/readh.html

Arosha
  • 1,311
  • 2
  • 16
  • 22