Qual é uma maneira eficiente de converter tamanhos legíveis em quantidades de bytes?

Qual é uma maneira eficiente de converter tamanhos legíveis em quantidades de bytes?

Gostaria de converter a saída ZFS de "10.9T" em bytes reais, usando algo em uma ou duas linhas, em vez de executar funções matemáticas genéricas e se houver condições para T,,, etc. ?GM

Por enquanto, tenho algo assim:

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

Isso produz um erro: não é possível executar a expressão 10.9Tou 50Gporque não são números.

Existe uma bashfunção conhecida para isso?

Também gosto da conveniência de especificá-lo como fiz na MINFREEvar no topo. Portanto, uma maneira fácil de converter seria boa.

Esseé o que eu esperava evitar (defendendo cada letra), mas o script parece limpo.

Editar: Obrigado por todos os comentários! Aqui está o código que tenho agora. , pelo menos partes relevantes;

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

Responder1

Não há uma boa maneira de converter zfsnúmeros legíveis por humanos em bytes reais. Os números legíveis por humanos são arredondados e, portanto, inexatos.

Se você quiser números exatos, use a -popção (analisável por máquina), e a saída será em bytes, que você pode analisar e formatar como desejar.

$ 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

Mas analisar zfsa saída legível por humanos e converter em números "exatos" não é possível. Como os números legíveis por humanos são especificados apenas para (digamos) três algarismos significativos, sua extrapolação "exata" também será precisa apenas para três algarismos.

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

Responder2

Você pode usarnumfmt(no Debian e derivados faz parte, coreutilsentão já deveria estar lá):

numfmt - Converte números de/para strings legíveis por humanos

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

também pode ler o valor de stdin

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

Tenha cuidado, pois leva em consideração a localidade do separador decimal.

Responder3

zpool listpode fornecer os números em bytes. por exemplo, listando três pools (15T, 29T e 416G) em meu servidor zfs principal.

Primeiro, sem -He -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%

E novamente, com -He-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

A saída é separada por tabulações, portanto é facilmente processada com awkou cuto que você quiser (até mesmo um shell durante o loop de leitura, se vocêinsistir). O capacitycampo é a porcentagem usada, portanto é particularmente útil se você deseja enviar um alerta por e-mail se um pool ficar abaixo de 10% ou 20% gratuito.

  • -HéScripted mode. Do not display headers, and separate fields by a single tab instead of arbitrary space.
  • -pimprime formato "analisável" em oposição ao formato "legível por humanos" (ou seja, bytes)

Aliás, as versões recentes do ZFS têm as zfspáginas zpoolman divididas em páginas separadas para seus subcomandos, propriedades, conceitos, etc. Se é isso que você está executando, consulte as páginas man para zpool-listobter zpoolpropsmais detalhes. Caso contrário, apenas man zpool.

Responder4

Como está marcado e redigido com basheu coloco isso para me divertir.

Sem validação. (Ou seja, se a unidade existir, etc.)

Quantidade 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

Quantidade base IEC 1024 (2 ^ 10) (usando 2 casas decimais)

Máx. 81.914P (64 bits) (8.191 se usar 3 casas decimais 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

informação relacionada