Jaki jest maksymalny rozmiar wartości zmiennej środowiskowej?

84

Czy istnieje ograniczenie ilości danych, które można przechowywać w zmiennej środowiskowej w systemie Linux, a jeśli tak, to co to jest?

W przypadku systemu Windows znalazłem następujący artykuł KB, który podsumowuje: Windows XP lub nowszy: 8191 znaków Windows 2000 / NT 4.0: 2047 znaków

Gio
źródło
Rzeczywisty limit dla okien wynosi 31 767. Czytałeś o setpoleceniu, które ma limit linii poleceń do 8191 znaków. Zobacz ten artykuł w witrynie MSDN Jednak nadal jest to przypadkowe ograniczenie.
Christopher Currens
5
8191 nie jest przypadkowe. Jest 2 ^ 13 - 1.
Barnaby Dawson
AWS Lambda: całkowity rozmiar zbioru [zmiennych środowiskowych] nie przekracza 4 KB ( źródło )
Martin Thoma
1
@BarnabyDawson może Christopher miał to na myśli w tym sensie, że było to arbitralne?
0xC0000022L

Odpowiedzi:

76

Nie sądzę, że istnieje limit zmiennych środowiskowych w systemie Linux. Całkowity rozmiar wszystkich połączonych zmiennych środowiskowych jest ograniczony w execve()czasie. Aby uzyskać więcej informacji, zobacz „Ograniczenia dotyczące rozmiaru argumentów i środowiska” tutaj .

Proces może wykorzystywać setenv()lub putenv()rozszerzać środowisko poza początkową przestrzeń przydzieloną przez exec.

Oto szybki i brudny program, który tworzy zmienną środowiskową 256 MB.

sigjuice
źródło
5
+1 dla informacji o execve (). W rzeczywistości możesz dodać zmienne środowiskowe do (co najmniej) 8M, ale wywołania exec () nie będą działać. W bashu objawia się to jako „lista argumentów jest zbyt długa” za każdym razem, gdy próbujesz uruchomić polecenie.
paxdiablo
1
Należy również pamiętać, że POSIX wymaga, aby ARG_MAX był co najmniej _POSIX_ARG_MAX, co powinno wynosić 4096.
ninjalj
10
Najlepsza odpowiedź (autorstwa Chipaca) na askUbuntu omawia użycie, xargs --show-limitsaby uzyskać więcej informacji.
DocSalvager,
Widzę też limit na ciąg arg - "Dodatkowo limit na łańcuch to 32 strony (stała jądra MAX_ARG_STRLEN)"
kiran01bm
24

Cóż, na moim pudełku jest co najmniej 4M. W tym momencie znudziłem się i odszedłem. Mam nadzieję, że wyjście terminala zostanie zakończone, zanim wrócę do pracy w poniedziałek :-)

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

Jeśli martwisz się, że 4M może nie wystarczyć dla zmiennej środowiskowej, możesz przemyśleć, jak robisz.

Być może lepszym pomysłem byłoby umieszczenie informacji w pliku, a następnie użycie zmiennej środowiskowej do odniesienia się do tego pliku. Widziałem przypadki, w których, jeśli zmienna ma postać @/path/to/any/fspec, pobiera rzeczywiste informacje z pliku path/to/any/fspec. Jeśli nie zaczyna się od @, używa wartości samej zmiennej środowiskowej.


Co ciekawe, gdy wszystkie te zmienne są ustawione, każde polecenie zaczyna narzekać, że lista argumentów jest zbyt długa, więc nawet jeśli pozwala je ustawić, może nie być w stanie uruchomić programów po wykonaniu tego (ponieważ musi przekazać środowisko do tych programów).

paxdiablo
źródło
1
Mam nadzieję, że użyłeś skryptu i nie wpisałeś tego wszystkiego ręcznie!
Chris Huang-Leaver,
2
Nie, stąd trochę „nudzić się”. Edycja wiersza poleceń w trybie Vi sprawiła, że ​​było to trochę łatwiejsze, ale pomyślałem, że może się nie powieść, zanim osiągnę znak 4M. C'est la vie.
paxdiablo
1
ale dlaczego zmienne ksh zatrzymują się na 256K ? Prawdopodobnie CentOS też
phuclv
@ LưuVĩnhPhúc: ponieważ programy mają ograniczenia. Mogą to być ograniczenia arbitralne lub oparte na dostępnych zasobach, ale ograniczenia istnieją. Całkiem możliwe DavidK zakłada jego powłoka nie będzie (nie-) używany przez szaleńców, którzy powinni wiedzieć lepiej :-)
paxdiablo
7

Zrobiłem szybki test na moim Linuksie z następującym fragmentem kodu:

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

Na moim komputerze (Gentoo 3.17.8-gentoo-r1) daje to (ostatnie wiersze wyniku):

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

A więc: limit jest dość wysoki!

cyberbird
źródło
1
18446744071562068096 bajtów to około 15 eksabajtów. :) Wydaje się, że to duży skok z 512MiB.
Marcus
1
@Marcus: to jest ... Domyślam się, że jakoś 1Gb czyli 1073741824 bajtów czyli 2 ^ 30 bajtów gdzieś przepełnia. Liczba bajtów w błędzie 18446744071562068096 jest dość bliska 2 ^ 64, czyli 18446744073709551616
cyberbird
1
Mam ograniczone umiejętności C / GDB, ale myślę, że problem tkwi w pliku źródłowym bash subst.c Funkcja sub_append_string (wiersz 726) używa podpisanej zmiennej int o nazwie n do obliczenia nowego rozmiaru. Nowy rozmiar (2 ^ 31) pasowałby, ale istnieje obliczenie wyrównania: n = (n + DEFAULT_ARRAY_SIZE) - (n % DEFAULT_ARRAY_SIZE); i podejrzewam, że część: (n + DEFAULT_ARRAY_SIZE)przepełnienia. Wszystko bardzo miłe, ale oczywiście jesteśmy tutaj poza wszelkimi rozsądnymi granicami ..
cyberbird
3

Oto dwa pomocne polecenia:

  • getconf -a |grep MAX

  • true | xargs --show-limits

dmitry_podyachev
źródło
Która z ~ 100 zmiennych jest odpowiednia? Gdzie są udokumentowane?
ingomueller.net
1

Nie wiem dokładnie, ale szybki eksperyment pokazuje, że żaden błąd nie występuje np. Przy 64kB wartości:

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

Użyłem tego bardzo szybkiego i brudnego kodu php (poniżej), modyfikując go dla różnych wartości i stwierdziłem, że działa on dla zmiennych długości do 128k. Potem z jakiegoś powodu nie działa; nie jest zgłaszany żaden wyjątek, nie jest zgłaszany żaden błąd, ale wartość nie jest wyświetlana w podpowłoce.

Może to jest limit specyficzny dla php? Może są ustawienia php.ini, które mogą na to wpłynąć? A może istnieje ograniczenie rozmiaru zmiennych, które odziedziczy podpowłoka? Może są odpowiednie ustawienia konfiguracji jądra lub powłoki.

W każdym razie, domyślnie w CentOS limit ustawiania zmiennej w środowisku przez putenv w php wydaje się wynosić około 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";
?>

Informacje o wersji -

[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
źródło
0

Linia poleceń (ze wszystkimi argumentami) plus zmienna środowiskowa powinna być mniejsza niż 128 KB.

J-16 SDiZ
źródło