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

一、问题

      格式化输出大数字,使得输出结果更清晰地看出数字的数量级。默认用逗号(可用-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/bash

SEPARATOR="."    #默认分割符
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"
		fi
		echo $result
}
#####函数入口####
#处理脚本标志参数
#./script -d . -t , 1123456789.012

#脚本标志参数处理命令: getopts	"d:t:" opt
#带两个参数,第一个参数为带解析的参数标志序列串(如-d,-t等),以冒号(:)表示该选项必须带参数value值
#第二个参数为:变量,每执行一次存放 参数标志序列串中的一个标志字符
#返回值:未解析结束返回0,解析结束返回1
while getopts "d:t:" opt
do
    case $opt in
        d) DD="$OPTARG" ;;  #$OPTARG为标志指定的参数值
        t) TD="$OPTARG" ;;  #可以之前初始化DD,TD,也可不初始化
        *) echo "no opt:$opt" >&2; exit 1 ;;
     esac
done
#内部变量$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
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

乌托邦2号

博文不易,支持的请给予小小打赏

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值