Переменная мощность Shell

Предположим, что у меня есть оболочка script, в которой есть оператор вроде:

a=$(find / -type f)

Это говорит о том, что существует определенный список файлов с файловыми путями, которые будут храниться в переменной 'a'.

Каков максимальный предел или количество строк, которые он может хранить. Как его найти?

Ответ 1

IIRC, bash не налагает ограничение на количество данных, которое может хранить переменная. Однако он ограничен средой, в которой выполнялось bash. См. этот ответ для более полного объяснения.

Ответ 2

В качестве отправной точки я попробовал следующий скрипт в OS X 10.10.5, используя встроенную утилиту bash на Macbook Pro Retina с процессором Intel Core i7 с частотой 2,8 ГГц:

#!/bin/bash

humombo="X"

while true; do
    humombo="$humombo$humombo"
    echo "Time $(date "+%H:%M:%S"), chars $(echo "$humombo" | wc -c)"
done

Результаты: размер снова и снова удваивается (обратите внимание, что размеры включают дополнительный байт для конца одной строки). Вещи начали замедляться, когда humombo прошел 4MB; удвоение с 256 МБ до 512 МБ заняло 48 секунд, и сценарий взорвался после этого:

mbpe:~ griscom$ ./delme.sh 
Time 16:00:04, chars        3
Time 16:00:04, chars        5
Time 16:00:04, chars        9
Time 16:00:04, chars       17
Time 16:00:04, chars       33
Time 16:00:04, chars       65
Time 16:00:04, chars      129
Time 16:00:04, chars      257
Time 16:00:04, chars      513
Time 16:00:04, chars     1025
Time 16:00:04, chars     2049
Time 16:00:04, chars     4097
Time 16:00:04, chars     8193
Time 16:00:04, chars    16385
Time 16:00:04, chars    32769
Time 16:00:04, chars    65537
Time 16:00:04, chars   131073
Time 16:00:04, chars   262145
Time 16:00:04, chars   524289
Time 16:00:04, chars  1048577
Time 16:00:04, chars  2097153
Time 16:00:05, chars  4194305
Time 16:00:05, chars  8388609
Time 16:00:07, chars  16777217
Time 16:00:09, chars  33554433
Time 16:00:15, chars  67108865
Time 16:00:27, chars  134217729
Time 16:00:51, chars  268435457
Time 16:01:39, chars  536870913
bash(80722,0x7fff77bff300) malloc: *** mach_vm_map(size=18446744071562072064) failed (error code=3)
*** error: can't allocate region
*** set a breakpoint in malloc_error_break to debug
./delme.sh: xrealloc: cannot allocate 18446744071562068096 bytes
mbpe:~ griscom$ 

Две заметки:

  • Я подозреваю, что сбой был больше, потому что весь процесс занял слишком много памяти, а не достиг предела единственной переменной емкости.

  • Играя с этим, я выполнял те же команды в интерактивном режиме, и когда выход из цикла завершился, bash был прерван; Я должен был открыть новое окно терминала, чтобы сделать что-нибудь. Таким образом, слишком большое выделение памяти нарушает работу bash неизвестными способами; Я предполагаю, что выполнение этого в сценарии очищается при выходе.

Изменить: я только что попробовал тот же код на мощной системе Ubuntu 18:

Time 18:03:02, chars 3
Time 18:03:02, chars 5
Time 18:03:02, chars 9
Time 18:03:02, chars 17
Time 18:03:02, chars 33
Time 18:03:02, chars 65
Time 18:03:02, chars 129
Time 18:03:02, chars 257
Time 18:03:02, chars 513
Time 18:03:02, chars 1025
Time 18:03:02, chars 2049
Time 18:03:02, chars 4097
Time 18:03:02, chars 8193
Time 18:03:02, chars 16385
Time 18:03:02, chars 32769
Time 18:03:02, chars 65537
Time 18:03:02, chars 131073
Time 18:03:02, chars 262145
Time 18:03:02, chars 524289
Time 18:03:02, chars 1048577
Time 18:03:02, chars 2097153
Time 18:03:02, chars 4194305
Time 18:03:02, chars 8388609
Time 18:03:03, chars 16777217
Time 18:03:04, chars 33554433
Time 18:03:07, chars 67108865
Time 18:03:12, chars 134217729
Time 18:03:23, chars 268435457
Time 18:03:43, chars 536870913
./delme.sh: xrealloc: cannot allocate 18446744071562068096 bytes

На это ушло меньше половины времени, и он умер немного чище, но с тем же размером символов. (Кстати, число в сообщении об ошибке, десятичное 18446744071562068096, равно 0xffff ffff 8000 0080, поэтому очевидно, что здесь мы достигаем некоторых ограничений по количеству.)

Ответ 3

Я не думаю, что существует ограничение на размер переменной в bash, но вам действительно нужна переменная 6 ГБ в вашей оболочке (suject to ulimit -a, конечно)?

Конечно, в командной строке есть предел. grep <pattern> $TEN_MILLION_FILENAMES не будет работать. На самом деле очень сложно выполнить любую команду, не создавную с помощью $TEN_MILLION_FILES. Вам нужны другие стратегии, такие как выполнение этого для каждого каталога, или временные файлы & c.

Ответ 4

Как я знаю, единственный способ найти предел - это эмпирически. Попробуйте запустить следующую оболочку script и дождитесь окончания:

limit=1
while true
do
  limit=`echo 1+$limit|bc`
  a=' '$a
  echo $limit
done

Ответ 5

Насколько я вижу, стандарт не налагает никаких ограничений. Но базовая система может. Я вспоминаю, что однажды я столкнулся с лимитом на какой-то AIX.

Вы можете проверить, как configure проверяет максимальное количество аргументов - попробуйте, пока не найдете ошибку. Какой-то итерационный подход с формулой var(i)=concatenation(var(i-1),var(i-1)). Рано или поздно вы достигли предела (по крайней мере, предел памяти при обработке).

Ответ 6

Небольшое улучшение сценария Дэниела Грискома:

  1. Вы можете добавить, показывающий, сколько памяти использует скрипт (см. добавленную последнюю команду в цикле)
  2. вы можете попробовать разные среды оболочки (мои тесты показали, что bash использует примерно в 5 раз больше памяти для переменной того же размера, что и zsh - вы можете самостоятельно выполнить приведенные ниже тесты)

ПРИМЕЧАНИЕ: строка "VmPeak" будет иметь пустой вывод при запуске скрипта внутри Cygwin, так как cygwin не полностью реплицирует /proc (в основном значение "VmPeak" отсутствует, но вы можете перейти к "VmSize", возможно, в таком случае?)

$ cat delme.sh
#!/bin/zsh

humombo="X"
pid=$$
while true; do
    humombo="$humombo$humombo"
    echo "Time $(date "+%H:%M:%S"), chars $(echo "$humombo" | wc -c)"
    echo -n "Memory usage: "
    grep ^VmPeak /proc/${pid}/status
done