程序員常常犯的一個錯誤是:在向用戶顯示計算的結果時,並無在第一時間格式化好它們。若是用戶沒有從右向左手動計數,而後在內心每三個數字就插入一個逗號的話,是很難界定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