Есть ли команда bash, которая может определить размер переменной оболочки

есть ли способ найти размер (используемая память) переменной оболочки из командной строки без использования C ?

4 ответов


wc может сказать вам, сколько символов и байтов находятся в переменной, а сам bash может сказать вам, сколько элементов находится в массиве. Если вы ищете, насколько велики внутренние структуры bash для хранения определенной переменной, то я не верю, что это доступно где-либо.

$ foo=42
$ bar=(1 2 3 4)
$ echo -n "$foo" | wc -c -m
      2       2
$ echo "${#bar[@]}"
4

это говорит вам, сколько символов в значении скалярной переменной с именем "var":

echo ${#var}

это говорит вам о количестве элементов в массиве с именем "array":

echo ${#array[@]}

это говорит вам количество символов в элементе массива:

echo ${#array[3]}

если вы пытаетесь получить размер массива, и вы покидаете [@] индекс, вы получаете длину элемента 0:

$ array=(1 22 333 4444)
$ echo ${#array}
1
$ echo ${#array[@]}
4
$ echo ${#array[2]}
3

если вы хотите общую длину всех элементы массива, вы можете перебирать массив и добавлять их, вы можете использовать IFS и некоторые шаги, подобные тем ниже, или вы могли бы:

$ tmp="${array[*]}"
$ echo $(( ${#tmp} - ${#array[@]} + 1 ))
10

остерегайтесь использовать количество элементов в массиве в качестве индекса последнего элемента, так как Bash поддерживает разреженные массивы:

$ array=(1 22 333 4444 55555)
$ echo ${#array[@]}
5
$ array[9]=999999999
$ echo ${#array[@]}
6
$ echo ${array[${#array[@]} - 1]}    # same as echo ${array[6 - 1]}

$ # only a newline is echoed since element 5 is empty (only if "nounset" option* is not set (default in most cases))
$ # when "nounset" option is set (possibly using command "set -u") then bash will print such error:
$ # bash: array[${#array[@]} - 1]: unbound variable
$ unset "array[1]"    # always quote array elements when you unset them
$ echo ${#array[@]}
5
$ echo ${array[${#array[@]} - 1]}    # same as echo ${array[5 - 1]}
55555

это был явно не последний элемент. Чтобы получить последний элемент:

$ echo ${array[@]: -1}    # note the space before the minus sign
999999999

обратите внимание, что в предстоящем Bash 4.2 вы можете сделать echo ${array[-1]} получить последнюю элемент. В версиях до 4.2 вы получаете плохую ошибку индекса для отрицательных индексов.

чтобы получить индекс последнего элемента:

$ idx=(${!array[@]})
$ echo ${idx[@]: -1}
9

затем вы можете сделать:

$ last=${idx[@]: -1}
$ echo ${array[last]}
999999999

для итерации по разреженному массиву:

for idx in ${!array[@]}
do
    something_with ${array[idx]}
done

* я рекомендую избегать nounset


${#VAR}

сообщает вам длину строки VAR


для скалярной переменной,${#VAR} дает вам длину в символах. В unibyte locale это длина в байтах. Размер в байтах-это длина имени в байтах плюс длина значения в байтах плюс постоянные накладные расходы.

LC_ALL=C
name=VAR
size=$(($#name + $#VAR)) # plus a small overhead

если переменная экспортируется, размер примерно в два раза.

LC_ALL=C
name=VAR
size=$((($#name + $#VAR) * 2)) # plus a small overhead

для переменной массива, нужно суммировать длины (в байтах) элементов, и добавить постоянные накладные расходы на каждый элемент плюс постоянные накладные расходы для массива.

LC_ALL=C
name=VAR
size=$(($#name)) # plus a small overhead
for key in "${!VAR[@]}"; do
  size=$((size + ${#key} + ${#VAR[$key]})) # plus a small overhead
done

вот минимально проверенная функция, которая вычисляет приблизительный размер, занимаемый переменной. Массивы и экспорт учитываются, но не специальные переменные только для чтения, такие как $RANDOM. Размеры наблюдались на bash 4.2, различные версии могут иметь различные накладные расходы. Вам может потребоваться настроить константы в зависимости от типов вашей системы и malloc реализация.

_sizeof_pointer=4
_sizeof_int=4
_malloc_granularity=16
_malloc_overhead=16
## Usage: compute_size VAR
## Print the amount of memory (in bytes) used by VAR.
## The extra bytes used by the memory allocator are not taken into account.
add_size () {
  local IFS="+" this extra
  set $(( + _malloc_overhead))
  _size=$((_size + ))
  set $(( % _malloc_granularity))
  [[  -eq 0 ]] || _size=$((_size + _malloc_granularity - ))
}
compute_size () {
  local LC_ALL=C _size=0 _key
  if eval "[ -z ${+1} ]"; then echo 0; return; fi
  add_size $((_sizeof_pointer*5 + _sizeof_int*2)) # constant overhead
  add_size ${#1} # the name
  case $(declare -p ) in
    declare\ -x*)
      eval "add_size ${#}" # the value
      eval "add_size $((${#1} + ${#} + 2))" # the export string
      ;;
    declare\ -a*)
      eval 'for _key in "${!''[@]}"; do
              add_size $_key
              add_size ${#''[$_key]}
              add_size $((_sizeof_pointer*4))
            done'
      add_size $((_sizeof_pointer*2 + _sizeof_int*2))
      add_size $((_sizeof_pointer*4))
      ;;
    *)
      eval "add_size ${#}" # the value
      ;;
  esac
  echo $_size
}