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. ?G
M
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.9T
ou 50G
porque não são números.
Existe uma bash
função conhecida para isso?
Também gosto da conveniência de especificá-lo como fiz na MINFREE
var 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 zfs
nú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 -p
opçã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 zfs
a 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, coreutils
entã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 list
pode fornecer os números em bytes. por exemplo, listando três pools (15T, 29T e 416G) em meu servidor zfs principal.
Primeiro, sem -H
e -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 -H
e-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 awk
ou cut
o que você quiser (até mesmo um shell durante o loop de leitura, se vocêinsistir). O capacity
campo é 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.
-p
imprime 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 zfs
páginas zpool
man divididas em páginas separadas para seus subcomandos, propriedades, conceitos, etc. Se é isso que você está executando, consulte as páginas man para zpool-list
obter zpoolprops
mais detalhes. Caso contrário, apenas man zpool
.
Responder4
Como está marcado e redigido com bash
eu 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