¿Cuál es una forma eficiente de convertir tamaños legibles por humanos en cantidades de bytes?

¿Cuál es una forma eficiente de convertir tamaños legibles por humanos en cantidades de bytes?

Me gustaría convertir la salida ZFS de "10.9T" a bytes reales, usando algo en una línea o dos, en lugar de ejecutar funciones matemáticas genéricas y condiciones para T,,, etc. ¿Existe una manera eficiente de hacer esto G? M?

Por ahora tengo algo como esto:

MINFREE="50G"
POOLSIZE=`zpool list $POOLNAME -o size` #Size 10.9T
POOLSIZE=$(echo "$POOLSIZE" | grep -e [[:digit:))]  #10.9T
POOLFREE=500M #as an example
let p=POOLSIZE x=POOLFREE y=MINFREE z=POOLSIZE; 
CALC=$(expr "echo $((x / y))")


if [ "${CALC}" < 1 ]; then
  # we are less than our min free space
  echo alert
fi

Esto produce un error: no se puede ejecutar la expresión en 10.9To 50Gporque no son números.

¿Existe alguna bashfunción conocida para esto?

También me gusta la conveniencia de especificarlo como lo hice en la MINFREEvar en la parte superior. Entonces, una manera fácil de convertir sería buena.

Estees lo que esperaba evitar (presentando argumentos para cada letra), aunque el guión parece limpio.

Editar: ¡Gracias por todos los comentarios! Aquí está el código que tengo ahora. , partes relevantes al menos;

POOLNAME=san
INFORMAT=auto
#tip; specify in Gi, Ti, etc.. (optional)
MINFREE=500Gi
OUTFORMAT=iec
NOW=`date`;
LOGPATH=/var/log/zfs/zcheck.log
BOLD=$(tput bold)
BRED=${txtbld}$(tput setaf 1)
BGREEN=${txtbld}$(tput setaf 2)
BYELLOW=${txtbld}$(tput setaf 3)
TXTRESET=$(tput sgr0);

# ZFS Freespace check
#poolsize, how large is it
POOLSIZE=$(zpool list $POOLNAME -o size -p)
POOLSIZE=$(echo "$POOLSIZE" | grep -e [[:digit:]])
POOLSIZE=$(numfmt --from=iec $POOLSIZE)
#echo poolsize $POOLSIZE

#poolfree, how much free space left
POOLFREE=`zpool list $POOLNAME -o free`
#POOLFREE=$(echo "$POOLFREE" | grep -e [[:digit:]]*.[[:digit:]].)
POOLFREE=$(echo "$POOLFREE" | grep -e [[:digit:]])
POOLFREE=$(numfmt --from=$INFORMAT $POOLFREE)
#echo poolfree $POOLFREE
#grep -e "vault..[[:digit:]]*.[[:digit:]].")

#minfree, how low can we go, before alerting
MINFREE=$(numfmt --from=iec-i $MINFREE)
#echo minfree $MINFREE


#FORMATTED DATA USED FOR DISPLAYING THINGS
#echo formattiing sizes:
F_POOLSIZE=$(numfmt --from=$INFORMAT --to=$OUTFORMAT  $POOLSIZE)
F_POOLFREE=$(numfmt --from=$INFORMAT --to=$OUTFORMAT $POOLFREE)
F_MINFREE=$(numfmt --from=$INFORMAT --to=$OUTFORMAT $MINFREE)
F_MINFREE=$(numfmt --from=$INFORMAT --to=$OUTFORMAT $MINFREE)
#echo
printf "${BGREEN}$F_POOLSIZE - current pool size"
printf "\n$F_MINFREE - mininium freespace allowed/as specified"

# OPERATE/CALCULATE SPACE TEST
#echo ... calculating specs, please wait..
#let f=$POOLFREE m=$MINFREE x=m/f;
declare -i x=$POOLFREE/$MINFREE;
# will be 0 if has reached low threshold, if poolfree/minfree
#echo $x
#IF_CALC=$(numfmt --to=iec-i $CALC)
if ! [ "${x}" == 1 ]; then
  #printf "\n${BRED}ALERT! POOL FREESPACE is low! ($F_POOLFREE)"
  printf "\n${BRED}$F_POOLFREE ${BYELLOW}- current freespace! ${BRED}(ALERT!}${BYELLOW} Is below your preset threshold!";
  echo
else
  printf "\nPOOLFREE - ${BGREEN}$F_POOLFREE${TXTRESET}- current freespace";
  #sleep 3
fi

Respuesta1

No existe una buena manera de convertir zfslos números legibles por humanos en bytes reales. Los números legibles por humanos están redondeados y, por lo tanto, son inexactos.

Si desea números exactos, use la -popción (analizable por máquina) y la salida será en bytes, que podrá analizar y formatear como desee.

$ zfs list tank/var; zfs list -p tank/var
NAME       USED  AVAIL     REFER  MOUNTPOINT
tank/var  8.33G   387G     6.90G  /var
NAME            USED         AVAIL       REFER  MOUNTPOINT
tank/var  8948584448  415137447936  7407120384  /var

Pero zfsno es posible analizar la salida legible por humanos y convertirla a números "exactos". Dado que los números legibles por humanos solo se especifican en (digamos) tres cifras significativas, su extrapolación "exacta" también será precisa solo en tres cifras.

TiB=$((2**40))
GiB=$((2**30))

# MINFREE=$((50*$TiB)) # 50 TiB
MINFREE=$((50*$GiB))   # 50 GiB

POOLFREE=$(zpool list -Hpo free "$POOLNAME") #Free in bytes

if [ "$POOLFREE" -lt "$MINFREE" ]; then
  printf "alert\n"
else
  printf "no alert -- %d bytes free >= %d byte minimum\n" "$POOLFREE" "$MINFREE"
fi

Respuesta2

Puedes usarnumfmt(en Debian y derivados forma parte, coreutilspor lo que ya debería estar allí):

numfmt - Convierte números de/a cadenas legibles por humanos

$ numfmt --from=iec-i 50.1Gi
53794465383

también puede leer el valor de stdin

$ echo "50.1Gi" | numfmt --from=iec-i
53794465383

Tenga cuidado, tiene en cuenta la configuración regional del separador decimal.

Respuesta3

zpool listPuede proporcionar los números en bytes. por ejemplo, enumerar tres grupos (15T, 29T y 416G) en mi servidor zfs principal.

Primero, sin -Hy -p:

$ zpool list -o name,size,alloc,free,capacity
NAME     SIZE  ALLOC   FREE    CAP
backup  14.5T  6.15T  8.40T    42%
export    29T  17.8T  11.2T    61%
ganesh   416G   169G   247G    40%

Y de nuevo, con -Hy-p

$ zpool list -H -p -o name,size,alloc,free,capacity
backup  15994458210304  6763872280576   9230585929728   42
export  31885837205504  19592775573504  12293061632000  61
ganesh  446676598784    181604904960    265071693824    40

La salida está separada por tabulaciones, por lo que se procesa fácilmente con awko cuto lo que quieras (incluso un ciclo shell while read si lo deseas).insistir). El capacitycampo es el porcentaje utilizado, por lo que es particularmente útil si desea enviar una alerta por correo electrónico si un grupo está por debajo del 10 % o 20 % gratuito.

  • -HesScripted mode. Do not display headers, and separate fields by a single tab instead of arbitrary space.
  • -pimprime un formato "analizable" en lugar de "legible por humanos" (es decir, bytes)

Por cierto, las versiones recientes de ZFS tienen las páginas de manual zfsy zpooldivididas en páginas separadas para sus subcomandos, propiedades, conceptos, etc. Si eso es lo que está ejecutando, consulte las páginas de manual para zpool-listobtener zpoolpropsmás detalles. De lo contrario, simplemente man zpool.

Respuesta4

Como está etiquetado y redactado, bashlo incluyo por diversión.

Sin validación. (Es decir, si la unidad existe, etc.)

Cantidad base SI 1000 (10^3):

#!/bin/bash

declare -A s=([Y]=24 [Z]=21 [E]=18 [P]=15 [T]=12 [G]=9 [M]=6 [K]=3)

input="$1"
suffix="${input: -1}"
number="${input:0: -1}"

printf "%.0f bytes\n" "${number}e+${s[$suffix]}"
$ ./bashsize10 1.6T
1600000000000 bytes

$ ./bashsize10 3681.914Y
3681914000000000000130023424 bytes

Cantidad base IEC 1024 (2^10) (usando 2 decimales)

Máx. 81.914P (64 bits) (8.191 si usa 3 decimales, etc.)

#!/bin/bash

declare -A s=([P]=50 [T]=40 [G]=30 [M]=20 [K]=10)

input="$1"
suffix="${input: -1}"
number="${input:0: -1}"
d=$(printf "%.0f" "${number}e+2")

printf "%d bytes\n" "$(( d * 2 ** s["$suffix"] / 100 ))"
$ ./bashsize2 1.6T
1759218604441 bytes

información relacionada