程序员常常犯的一个错误是:在向用户显示计算的结果时,并无在第一时间格式化好它们。若是用户没有从右向左手动计数,而后在内心每三个数字就插入一个逗号的话,是很难界定43245435这个数字有没有达到百万的(英文中的数字记法,若是是汉语的话,我的以为仍是4个数字插入一个逗号更好读点,若是汉语须要这样计数的话)。使用下面这个脚原本格式化你的计算结果。 git
nicenumber.sh #!/bin/sh # nicenumber.sh -- 给定一个数字,将它用逗号分隔的形式表示出来 # 以DD和TD做为实例。实例化nicenumber.sh,若是指定了第二个参数,会产生一个标准输出。 nicenumber() { # 注意,在输入中假定点号是十进制的小数位。 # 输出中的十进制分隔符是点号,除非用户使用了 -d 选项。 integer=$(echo $1 | cut -d. -f1) # 小数点左边 decimal=$(echo $1 | cut -d. -f2) # 小数点右边 if [ $decimal != $1 ]; then # 这里有个小数部分,将它包含进去 result="${DD:="."}$decimal" fi thousands=$integer while [ $thousands -gt 999 ]; do remainder=$(($thousands%1000)) # 3个最低有效位数字 while [ ${#remainder} -lt 3 ]; do # 若是须要,强制以0打头 remainder="0$remainder" done thousands=$(($thousands/1000)) # remainder左侧数字,若是有 result="${TD:=","}${remainder}${result}" # 从右向左生成 done nicenum="${thousands}${result}" if [ ! -z $2 ]; then echo $nicenum fi } DD="." # 十进制的点分隔符,区分整数部分和小数部分 TD="," # 千位分隔符,每三个数字添加一个 while getopts "d:t:" opt; do # 下面会详谈getopts的用法,它很特殊,但很强力 case $opt in d)DD="$OPTARG";; t)TD="$OPTARG";; esac done shift $(($OPTIND-1)) if [ $# -eq 0 ]; then echo "Usage: $(basename $0)[-d c] numeric value" echo " -d 指定十进制的小数位分隔符(默认是点号)" echo " -t 指定了千位分隔符(默认是逗号)" fi nicenumber $1 1 # 第二个参数强制 nicenumber 输出到标准输出 exit 0
脚本如何工做:
这个脚本的核心是nicenumber函数中的while循环。该函数得到数值,而后循环将它分割为3个最低有效位数字(也就是会出如今下一个逗号右边的3个数字),以及保留的数值。接着,这些最低有效位又会经过循还进行处理。 程序员
运行代码:
要运行这个脚本,只需简单指定一个很是大的数值,而后脚本就会根据须要,要么使用默认的要么按照标志位指定(-d或-t)的,来增长小数分隔符和千位分隔符。由于函数的输出是一个数字,因此结果能够像下面这样:echo "Do you really want pay $(nicenumber $price) dollars?" shell
运行结果: ide
./nicenumber.sh 5894625 5,894,625 ./nicenumber.sh 589462532.433 589,462,532.433 ./nicenumber.sh -d, -t. 589462532.433 589.462.532,433 ./newnicenum.sh Usage: newnicenum.sh [-d c] [-t c] numeric value -d 指定十进制的小数位分隔符(默认是点号) -t 指定了千位分隔符(默认是逗号)
延伸阅读:
不一样的国家使用的小数位分隔符和千位分隔符是不一样的,所以须要增长标志位来灵活的指定。好比,德国和意大利会使用-d "."和-t ",",法国会用-d ","和-t " ",而瑞士有4种语言,他们会用-d "."和-t ""。这个例子很好的展现了灵活应用是如何优于写死代码的,因此这个脚本工具彻底能够适用于大多数国家的用户。另外一方面,该脚本中把输入中的小数位分隔符写死为点号,若是你预计输入中的小数位使用不一样的分隔符,你能够把两个调用cut命令中的指定分隔符给改变。看下面: 函数
integer=$(echo $1 | cut "-d$DD" -f1) #小数位左侧 decimal=$(echo $1 | cut "-d$DD" -f2) #小数位右侧
这样能够运行,但若是使用一个彻底不一样的小数分隔符的话,就不那么完美了。一个更加精妙的解决方法是在这2行代码前面先测试下,以此来确保预期的小数位分隔符是用户所要求的。咱们能够学习第2个脚本中的思想,用sed删除全部数字,看看剩下的是什么: 工具
1 seperator="$(echo $1 | sed 's/[[:digit:]]//g')" 2 if [ !-z "$seperator" -a "$seperator" != "$DD"]; then 3 echo "$0: Unknown decimal seperator $seperator encounted." >&2 4 exit 1 5 fi
我的心得: 学习
1.cut中的分隔符是-d选项,-f是指的域。想一想awk。这个就是简化版。
2.在Shell脚本中对于字符串的引用--引号和大括号。
3.getopts:分析传递到脚本中的命令行参数的最强力工具 测试
getopts具备如下特色:
1.全部传递到脚本中的参数,前面必须加上一个减号【-】,getopts是不会处理不带-前缀的参数的。
2.getopts通常放在一个while循环中,而这个while循环和标准的while循环有些不一样,它是没有中括号[]判断的。
3.getopts将会取代外部命令getopt
在本脚本中使用的getopts结构的说明:
d和t都被认为是标志选项,d后面跟一个冒号,说明该选项要带一个参数,同理t。 ui
shift $(($OPTIND-1))
上句的做用是参数指针向下移动一位。shift是能够带参数的,参数是移动的个数。将参数指针OPTIND减1,就是指向下一个参数的意思。这时候,$1指向第一个非选项参数了。
如何理解它,看我作个测试: spa
1 ./newnicenum.sh -d. -t 589462532.345 2 而后打印 3 Usage: newnicenum.sh [-d c] [-t c] numeric value4 -d 指定十进制的小数位分隔符(默认是点号) 5 -t 指定了千位分隔符(默认是逗号)"
为何?由于 -t 后面没有跟上一个参数,还记得getopts中 t 后面的冒号吗?因此589462532.345被认为是t的参数,而后$1指向为空了,由于这个数字参数被shift掉了。因此$#(即参数个数)等于0了,打印3条语句。
再测试下:
1 ./newnicenum.sh -d -t, 589462532.345 2 而后打印 3 ./newnicenum.sh: Unknown decimal seperator . encounted.
为何不打印那3句话了?由于它认为小数位分隔符是点号,而$DD是为空的($DD是在getopts中赋值的,为空),它俩不一样,因此符合nicenumber函数中的开头的if判断语句中-a后面的条件。
注:以上关于getopts的说明参考了"Advanced Bash-Scripting Guide"。
汇总下延伸中的内容,最终脚本以下:
#!/bin/sh nicenumber() { # 注意,在输入中假定点号是十进制的小数位。 # 输出中的十进制分隔符是点号,除非用户使用了 -d 选项。 seperator="$(echo $1 | sed 's/[[:digit:]]//g')" if [ ! -z "$seperator" -a "$seperator" != "$DD" ]; then echo "$0: Unknown decimal seperator $seperator encounted." >&2 exit 1 fi integer=$(echo $1 | cut "-d$DD" -f1) #小数位左侧 decimal=$(echo $1 | cut "-d$DD" -f2) #小数位右侧 if [ $decimal != $1 ]; then # 这里有个小数部分,将它包含进去 result="${DD:="."}$decimal" fi thousands=$integer while [ $thousands -gt 999 ]; do remainder=$(($thousands%1000)) # 3个最低有效位数字 while [ ${#remainder} -lt 3 ]; do # 若是须要,强制以0打头 remainder="0$remainder" done thousands=$(($thousands/1000)) # remainder左侧数字,若是有 result="${TD:=","}${remainder}${result}" # 从右向左生成,:=的用法,是若是TD尚未设置,就将它的默认值设置为逗号 done nicenum="${thousands}${result}" if [ ! -z $2 ]; then echo $nicenum fi } DD="." # 十进制的点分隔符,区分整数部分和小数部分 TD="," # 千位分隔符,每三个数字添加一个 while getopts "d:t:" opt; do # 下面会详谈getopts的用法,它很特殊,但很强力 case $opt in d)DD="$OPTARG";; t)TD="$OPTARG";; esac done shift $(($OPTIND-1)) if [ $# -eq 0 ]; then echo "Usage: " $(basename $0) " [-d c] [-t c] numeric value" echo " -d 指定十进制的小数位分隔符(默认是点号)" echo " -t 指定了千位分隔符(默认是逗号)" fi nicenumber $1 1 # 第二个参数强制 nicenumber 输出到标准输出 exit 0