shell实例浅谈之九格式化输出大数字

来源:互联网 发布:a1 24ga发热丝双发数据 编辑:程序博客网 时间:2024/06/05 01:17

一、问题

      格式化输出大数字,使得输出结果更清晰地看出数字的数量级。默认用逗号(可用-d指定整数的分隔符)分隔整数部分,用点号(可用-t指定整数与小数的分隔符)分隔整数与小数部分。如1123456789.012输出为1,123,456,789.012。

二、详解

(1)算法

1123456789.012输出为1,123,456,789.012。

i、首先分开整数部分integer(cut-d. -f1取整数部分和小数部分decimal(cut -d. -f2取小数部分

ii、整数部分的处理:

方式一:当作数字来处理(使用%取模运算,/取余运算)

a、每次取整数低三位,长度小于3就补前缀0(避免出现漏0情况,例如003)。

b、将此次得到的三位与上一次得到的三位用分隔符(如果没有指定就默认)组合起来

c、整数去掉低三位,继续循环操作。当此整数小于等于999就不再继续,然后组合就得输出结果。

方式二:当作字符串来处理

a、每次取低三位,echo $str | cut -c$((${#str}-2))-${#str},${#str}str的长度,$((${#str}-2))相当于expr${#str}-2

b、原串每次都要裁掉尾部三个字符,每次取到的字串的长度为循环判断条件。

(2)代码

#!/bin/bashSEPARATOR="."    #默认分割符formatnumber()   #函数实现部分1123456789.012或者1123456789{    #检测传给脚本的大数值中是否含有非法的整小数分隔符,即存在与用户指定或默认分隔符不同的符号。    #方法:删除其中所有数字,看剩下的内容,若不空且不等于$DD,则非法    separator="$(echo $1 | sed 's/[[:digit:]]//g')"  if [[ -n $separator  &&  "$separator" != "$SEPARATOR" ]]  # 蓝色部分可用 –a 表示    then        echo "number is wrong,please input again!"    exit 1  fi        #分别取整数部分和小数部分,如    integer=$(echo $1 | cut -d. -f1)    decimal=$(echo $1 | cut -d. -f2)    #使脚本能够处理各种整数与小数各种分隔符情况,可修改为    #integer=$(echo $1 | cut -d${SEPARATOR:="."} -f1)  #decimal=$(echo $1 | cut -d${SEPARATOR:="."} -f2)    if [ -n $decimal ]  #非空,即有小数部分。    then        #等价于result="${DD:="."}$decimal"其中:=,若变量为空,可以使用:=设置一个默认值;不为空则为$DD的值。        if [ -z $DD ]        then            DD=.        fi        result=$DD$decimal    fi    thousand=$integer    while [ $thousand -gt 999 ]    do        remainder=$((thousand%1000))        while [ ${#remainder} -lt 3 ];do #${#remainder} 为remainder串的长度        remainder=0$remainder #避免remainder为00x时的丢0情况。      done        thousand=$(($thousand/1000))        #下四句等价于result="${TD:=","}$remainder$result"        if [ -z $TD ] ; then# 判断用户是否自定义整数分隔符, 若 空        TD=","      fi      result="$TD$remainder$result"# 与分隔符合成串。 注意顺序    done    if [ -n $thousand ]; then#若非空        result="$thousand$result"fiecho $result}#####函数入口#####处理脚本标志参数#./script -d . -t , 1123456789.012#脚本标志参数处理命令: getopts"d:t:" opt#带两个参数,第一个参数为带解析的参数标志序列串(如-d,-t等),以冒号(:)表示该选项必须带参数value值#第二个参数为:变量,每执行一次存放 参数标志序列串中的一个标志字符#返回值:未解析结束返回0,解析结束返回1while getopts "d:t:" optdo    case $opt in        d) DD="$OPTARG" ;;  #$OPTARG为标志指定的参数值        t) TD="$OPTARG" ;;  #可以之前初始化DD,TD,也可不初始化        *) echo "no opt:$opt" >&2; exit 1 ;;     esacdone#内部变量$OPTARG:每次解析标志对应的参数值,便默认存放在此变量内#内部变量$OPTIND:初始值是1,每次getopts处理完一个命令参数后就递增它,得到getopts要处理的下一个参数(也可以使用$#进行参数个数的处理,此时$*代表-d . -t , 1123456789.012和$#值为5)。#当执行shift 1时,各个位置参数的值向左移1次,此时$1的值为原$2的值,$2的值为原$3的值,依次类推shift $(($OPTIND - 1))formatnumber $1

三、总结

(1)该代码包含字符串和数字处理的不同方法,对长数据的处理还是有借鉴意义的。

(2)getopts比较适用,可以添加一系列的长参数,其内部变量OPTARG和OPTIND应充分理解,熟练使用$#和$*。

(3)本代码若有不完善的地方,可请大家留言,也可联系本人yang.ao@i-soft.com.cn。

1 0