2011-02-14 45 views

Respuesta

11

wc puede decirle cuántos caracteres y bytes hay en una variable, y bash mismo puede decirle cuántos elementos hay en una matriz. Si lo que estás buscando es qué tan grande son las estructuras internas de bash para contener una variable específica, entonces no creo que esté disponible en ninguna parte.

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

sólo puede escribir $ {foo #} para obtener la longitud de cuerda - comprobar mi @foo respuesta –

+0

: En caracteres, sí. No en bytes –

+0

Si realmente está buscando la memoria utilizada, necesita agregar la longitud del nombre y agregar algunos gastos generales. Y aproximadamente el doble para las variables exportadas. – Gilles

2
${#VAR} 

le indica la longitud de la cadena VAR

+0

Y para matrices puede expandirlas con '$ {ary [*]}' asigne eso a una variable de temperatura y use lo anterior para obtener el total de los valores. Además, use '$ {! Ary [*]}' para obtener una lista de las claves. Esto se está volviendo complicado, ¿no? – dmckee

+0

debe establecer IFS = "" para asegurarse de no introducir caracteres adicionales. Es un PITA, lo sé –

+0

Es cierto, pero está muy lejos de la memoria utilizada (en particular, menos de la mitad si la variable se exporta, y potencialmente menos en una configuración regional de varios bytes, ya que está contando caracteres y no bytes). – Gilles

17

Esto le indica la cantidad de caracteres en el valor de una variable escalar llamado "var":

echo ${#var} 

Esto le dice usted el número de elementos en una matriz llamada "matriz":

echo ${#array[@]} 

Esto le indica el número de caracteres en un elemento de una matriz:

echo ${#array[3]} 

Si intenta obtener el tamaño de una matriz y se omite el índice [@], se obtiene la longitud del elemento de 0:

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

Si desea que la longitud total de todos los elementos de una matriz, se puede iterar sobre la matriz y sumarlos, se puede usar IFS y algunos pasos similares a los de abajo, o usted podría:

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

Tenga cuidado de usar el número de elementos de un array como el índice del último elemento ya Bash es compatible con matrices dispersas:

$ 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 

que obviamente no era el último elemento. Para obtener el último elemento:

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

Tenga en cuenta que en el próximo Bash 4.2, que puede hacer echo ${array[-1]} para obtener el último elemento. En las versiones anteriores a 4.2, se obtiene un error de subíndice incorrecto para los subíndices negativos.

Para obtener el índice del último elemento:

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

entonces usted puede hacer:

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

para iterar sobre una matriz dispersa:

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

* Recomiendo evitar nounset

+0

No es tan simple ... Establecer 'LC_ALL = C' para contar bytes en lugar de cadenas, y está la memoria utilizada por el nombre de la variable (y las teclas, para las matrices), más algunas extra para las variables exportadas, más algunos gastos generales. – Gilles

+0

¡woo hoo! '$ (($ {# variable_name} + 1))' fue exactamente el patrón que estaba buscando. :) #different_context #random – user2533809

1

Para una variable escalar, ${#VAR} muestra la longitud en caracteres. En una configuración regional unibyte, esta es la longitud en bytes. El tamaño en bytes es la longitud del nombre en bytes, más la longitud del valor en bytes, más una carga general constante.

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

Si se exporta la variable, el tamaño es aproximadamente el doble.

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

Para una variable de matriz, es necesario para resumir las longitudes (de nuevo, en bytes) de los elementos, y añadir una sobrecarga constante por elemento más una sobrecarga constante para la matriz.

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 

Aquí hay una función mínimamente probada que calcula el tamaño aproximado ocupado por una variable. Se tienen en cuenta las matrices y las exportaciones, pero no las variables especiales de solo lectura como $RANDOM. Los tamaños se han observado en bash 4.2, las diferentes versiones pueden tener diferentes gastos generales. Es posible que deba ajustar las constantes según los tipos de su sistema y la implementación 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 $(($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 
} 
Cuestiones relacionadas