简体   繁体   中英

Is there a bash command that can tell the size of a shell variable

有没有办法从命令行中找到shell变量的大小(使用的内存),而不使用C?

This tells you how many characters are in the value of a scalar variable named "var":

echo ${#var}

This tells you the number of elements in an array named "array":

echo ${#array[@]}

This tells you the number of characters in an element of an array:

echo ${#array[3]}

If you try to get the size of an array and you leave out the [@] index, you get the length of element 0:

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

If you want the total length of all elements of an array, you could iterate over the array and add them up, you could use IFS and some steps similar to those below, or you could:

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

Beware of using the number of elements in an array as the index of the last element since Bash supports sparse arrays:

$ 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

That was obviously not the last element. To get the last element:

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

Note that in the upcoming Bash 4.2, you can do echo ${array[-1]} to get the last element. In versions prior to 4.2, you get a bad subscript error for negative subscripts.

To get the index of the last element:

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

Then you can do:

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

To iterate over a sparse array:

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

* I recommend avoiding nounset

wc can tell you how many characters and bytes are in a variable, and bash itself can tell you how many elements are in an array. If what you're looking for is how large bash's internal structures are for holding a specific variable then I don't believe that's available anywhere.

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

告诉你字符串VAR的长度

For a scalar variable, ${#VAR} gives you the length in characters. In a unibyte locale, this is the length in bytes. The size in bytes is the length of the name in bytes, plus the length of the value in bytes, plus a constant overhead.

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

If the variable is exported, the size is roughly double.

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

For an array variable, you need to sum up the lengths (again, in bytes) of the elements, and add a constant overhead per element plus a constant overhead for the array.

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

Here's a minimally tested function that computes the approximate size occupied by a variable. Arrays and exports are taken into account, but not special read-only variables such as $RANDOM . The sizes have been observed on bash 4.2, different versions may have different overheads. You may need to adjust the constants depending on your system types and malloc implementation.

_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 $(($1 + _malloc_overhead))
  _size=$((_size + $1))
  set $(($1 % _malloc_granularity))
  [[ $1 -eq 0 ]] || _size=$((_size + _malloc_granularity - $1))
}
compute_size () {
  local LC_ALL=C _size=0 _key
  if eval "[ -z \${$1+1} ]"; then echo 0; return; fi
  add_size $((_sizeof_pointer*5 + _sizeof_int*2)) # constant overhead
  add_size ${#1} # the name
  case $(declare -p $1) in
    declare\ -x*)
      eval "add_size \${#$1}" # the value
      eval "add_size \$((\${#1} + \${#$1} + 2))" # the export string
      ;;
    declare\ -a*)
      eval 'for _key in "${!'$1'[@]}"; do
              add_size $_key
              add_size ${#'$1'[$_key]}
              add_size $((_sizeof_pointer*4))
            done'
      add_size $((_sizeof_pointer*2 + _sizeof_int*2))
      add_size $((_sizeof_pointer*4))
      ;;
    *)
      eval "add_size \${#$1}" # the value
      ;;
  esac
  echo $_size
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM