将人类可读的大小转换为字节数量的有效方法是什么?

Bri*_*mas 14 bash text-processing

我想的“10.9T的” ZFS输出转换为实际字节,使用一两行的东西,而不是运行通用的数学函数,并且如果条件TGM,等有没有一种有效的方式来做到这一点?

现在,我有这样的事情:

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
Run Code Online (Sandbox Code Playgroud)

这会产生一个错误:无法在 上运行表达式10.9T,或者50G因为它们不是数字。

是否有已知的bash功能?

我也喜欢指定它的便利,就像我MINFREE在顶部的var 中所做的那样。所以一个简单的转换方法会很好。

是我希望避免的(为每个字母设置大小写),尽管脚本看起来很干净。

编辑:感谢所有评论!这是我现在拥有的代码。,至少相关部分;

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
Run Code Online (Sandbox Code Playgroud)

Jim*_* L. 41

没有将zfs的人类可读数字转换为实际字节的好方法。人类可读的数字被四舍五入,因此不准确。

如果您想要确切的数字,请使用-p选项(机器可解析),输出将以字节为单位,您可以根据需要对其进行解析和格式化。

$ 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
Run Code Online (Sandbox Code Playgroud)

但是解析zfs人类可读的输出并转换为“精确”数字是不可能的。由于人类可读的数字仅指定为(例如)三个有效数字,因此您的“精确”外推也将仅准确到三个数字。

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
Run Code Online (Sandbox Code Playgroud)

  • 这个!要求生成输出的程序以您需要的形式生成它。 (4认同)
  • `2**30` 是 *GiB。* `10**3` 是 GB。 (2认同)

Edu*_*ani 30

您可以使用numfmt(在 Debian 和衍生产品中,它是其中的一部分,coreutils因此它应该已经存在):

numfmt - 将数字从/转换为人类可读的字符串

$ numfmt --from=iec-i 50.1Gi
53794465383
Run Code Online (Sandbox Code Playgroud)

它还可以从标准输入读取值

$ echo "50.1Gi" | numfmt --from=iec-i
53794465383
Run Code Online (Sandbox Code Playgroud)

请注意,它会考虑小数点分隔符的区域设置。


cas*_*cas 9

zpool list可以提供以字节为单位的数字。例如,在我的主 zfs 服务器上列出三个池(15T、29T 和 416G)。

首先,没有-H-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%
Run Code Online (Sandbox Code Playgroud)

再次,与-H-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
Run Code Online (Sandbox Code Playgroud)

输出是制表符分隔的,因此很容易使用awkcut或您喜欢的任何东西进行处理(如果您坚持,甚至可以使用 shell while read 循环)。该capacity字段是使用的百分比,因此如果您想在池的免费率低于 10% 或 20% 时通过电子邮件发送警报,则该字段特别有用。

  • -HScripted mode. Do not display headers, and separate fields by a single tab instead of arbitrary space.
  • -p 打印“可解析”而不是“人类可读”格式(即字节)

顺便说一句,最近的ZFS的版本具有zfszpool手册页拆分成其子命令,属性,概念等,如果这就是你运行的是什么,请参阅手册页单独的页面zpool-list,并zpoolprops了解更多详情。否则,只是man zpool


ibu*_*fen 5

因为它被标记和措辞为,所以bash我把它扔进去是为了好玩。

没有验证。(即如果单位存在等)

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]}"
Run Code Online (Sandbox Code Playgroud)
$ ./bashsize10 1.6T
1600000000000 bytes

$ ./bashsize10 3681.914Y
3681914000000000000130023424 bytes
Run Code Online (Sandbox Code Playgroud)

IEC 基本数量 1024 (2^10)(使用 2 位小数)

最大 81.914P(64 位)(如果使用 3 位小数等则为 8.191)

#!/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 ))"
Run Code Online (Sandbox Code Playgroud)
$ ./bashsize2 1.6T
1759218604441 bytes
Run Code Online (Sandbox Code Playgroud)

  • @BrianThomas:是的。`numfmt` 是一个很好的工具。我相信你知道,bash 不能进行浮点运算。然而,“printf”可以处理电子符号。找到规避限制的方法很有趣,尽管通常是为了好玩 - 就像本文末尾的 bash 变体:https://unix.stackexchange.com/a/651945/140633 :P (2认同)