格式化計算結果的指令碼

來源:互聯網
上載者:User

格式化計算結果的指令碼  程式員經常犯的一個錯誤是:在向使用者顯示計算的結果時,並沒有在第一時間格式化好它們。如果使用者沒有從右向左手動計數,然後在心裡每三個數字就插入一個逗號的話,是很難界定43245435這個數字有沒有達到百萬的(英文中的數字記法,如果是漢語的話,個人覺得還是4個數字插入一個逗號更好讀點,如果漢語需要這樣計數的話)。使用下面這個指令碼來格式化你的計算結果。 01nicenumber.sh02 #!/bin/sh03 # nicenumber.sh -- 給定一個數字,將它用逗號分隔的形式表示出來04 # 以DD和TD作為執行個體。執行個體化nicenumber.sh,如果指定了第二個參數,會產生一個標準輸出。05  06 nicenumber()07 {08     # 注意,在輸入中假定點號是十進位的小數位。09     # 輸出中的十進位分隔字元是點號,除非使用者使用了 -d 選項。10  11     integer=$(echo $1 | cut -d. -f1)         # 小數點左邊12     decimal=$(echo $1 | cut -d. -f2)        # 小數點右邊13  14     if [ $decimal != $1 ]; then15         # 這裡有個小數部分,將它包含進去16         result="${DD:="."}$decimal"17     fi18  19     thousands=$integer20  21     while [ $thousands -gt 999 ]; do22         remainder=$(($thousands%1000))         # 3個最低有效位元字23  24         while [ ${#remainder} -lt 3 ]; do     # 如果需要,強制以0打頭25             remainder="0$remainder"26         done27  28         thousands=$(($thousands/1000))         # remainder左側數字,如果有29         result="${TD:=","}${remainder}${result}"     # 從右向左產生30     done31  32     nicenum="${thousands}${result}"33     if [ ! -z $2 ]; then34         echo $nicenum35     fi36 }37  38 DD="."     # 十進位的點分隔字元,區分整數部分和小數部分39 TD=","     # 千位分隔字元,每三個數字添加一個40  41 while getopts "d:t:" opt; do     # 下面會詳談getopts的用法,它很特殊,但很強力42     case $opt in43         d)DD="$OPTARG";;44         t)TD="$OPTARG";;45     esac46 done47 shift $(($OPTIND-1))48  49 if [ $# -eq 0 ]; then50     echo "Usage: $(basename $0)[-d c] numeric value"51     echo " -d 指定十進位的小數位分隔字元(預設是點號)"52     echo " -t 指定了千位分隔字元(預設是逗號)"53 fi54  55 nicenumber $1 1     # 第二個參數強制 nicenumber 輸出到標準輸出56  57 exit 0   指令碼如何工作:   這個指令碼的核心是nicenumber函數中的while迴圈。該函數獲得數值,然後迴圈將它分割為3個最低有效位元字(也就是會出現在下一個逗號右邊的3個數字),以及保留的數值。接著,這些最低有效位又會通過循還進行處理。    運行代碼:   要運行這個指令碼,只需簡單指定一個非常大的數值,然後指令碼就會根據需要,要麼使用預設的要麼按照標誌位指定(-d或-t)的,來增加小數分隔字元和千位分隔字元。因為函數的輸出是一個數字,所以結果可以像下面這樣:echo "Do you really want pay $(nicenumber $price) dollars?"    運行結果: 01./nicenumber.sh 589462502 5,894,62503 ./nicenumber.sh 589462532.43304 589,462,532.43305 ./nicenumber.sh -d, -t. 589462532.43306 589.462.532,43307 ./newnicenum.sh08 Usage: newnicenum.sh [-d c] [-t c] numeric value09  -d 指定十進位的小數位分隔字元(預設是點號)10  -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。 shift $(($OPTIND-1))上句的作用是參數指標向下移動一位。shift是可以帶參數的,參數是移動的個數。將參數指標OPTIND減1,就是指向下一個參數的意思。這時候,$1指向第一個非選項參數了。如何理解它,看我做個測試: 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"。 匯總下延伸中的內容,最終指令碼如下: 01#!/bin/sh02  03 nicenumber()04 {05     # 注意,在輸入中假定點號是十進位的小數位。06     # 輸出中的十進位分隔字元是點號,除非使用者使用了 -d 選項。07  08     seperator="$(echo $1 | sed 's/[[:digit:]]//g')"09     if [ ! -z "$seperator" -a "$seperator" != "$DD" ]; then10         echo "$0: Unknown decimal seperator $seperator encounted." >&211         exit 112     fi13  14     integer=$(echo $1 | cut "-d$DD" -f1)     #小數位左側15     decimal=$(echo $1 | cut "-d$DD" -f2)    #小數位右側16  17     if [ $decimal != $1 ]; then18         # 這裡有個小數部分,將它包含進去19         result="${DD:="."}$decimal"20     fi21  22     thousands=$integer23  24     while [ $thousands -gt 999 ]; do25         remainder=$(($thousands%1000))         # 3個最低有效位元字26  27         while [ ${#remainder} -lt 3 ]; do     # 如果需要,強制以0打頭28             remainder="0$remainder"29         done30  31         thousands=$(($thousands/1000))         # remainder左側數字,如果有32         result="${TD:=","}${remainder}${result}"  # 從右向左產生,:=的用法,是如果TD還沒有設定,就將它的預設值設定為逗號33     done34  35     nicenum="${thousands}${result}"36     if [ ! -z $2 ]; then37         echo $nicenum38     fi39 }40  41 DD="."     # 十進位的點分隔字元,區分整數部分和小數部分42 TD=","     # 千位分隔字元,每三個數字添加一個43  44 while getopts "d:t:" opt; do     # 下面會詳談getopts的用法,它很特殊,但很強力45     case $opt in46         d)DD="$OPTARG";;47         t)TD="$OPTARG";;48     esac49 done50 shift $(($OPTIND-1))51  52 if [ $# -eq 0 ]; then53     echo "Usage: " $(basename $0) " [-d c] [-t c] numeric value"54     echo " -d 指定十進位的小數位分隔字元(預設是點號)"55     echo " -t 指定了千位分隔字元(預設是逗號)"56 fi57  58 nicenumber $1 1     # 第二個參數強制 nicenumber 輸出到標準輸出59  60 exit 0 

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.