第一章:The Missing Code Library--3.正常化日期格式

   Shell腳本開發過程當中的一個不肯定的問題就是先後不一致的數據格式的數目。要正常化他們,可能很難也可能比較簡單。日期格式就是最有挑戰性的一種,由於一個日期能夠有多種特定方式的寫法。即便你提出了一個特定的格式,好比「月份 幾號 年份」,也有可能獲得一個不符合條件的輸入:月份是用的數字,而不是名稱,或是月份的名稱用的是一個縮寫(英文中好比11月是Nov.),再或是一個全是大寫的完整月份名。因爲這個緣由,一個正常化日期的函數,雖然自身還只是有點初級功能,可是之後會證明在一個更完備的腳本中會是多麼的有用處,特別是第7個腳本--正確化日期格式。 git

normdata.sh
 #!/bin/sh
 
 # normdata.sh -- 在日期中將月份正常化爲3個字母,第一個字母大寫。
 # 對於第7個腳本valid-date頗有幫助的函數。
 
 monthnoToName()
 {
     # 把變量'month'設置爲一個適當的值
     case $1 in
         1 ) month="Jan";;  2 ) month="Feb";; 
         3 ) month="Mar";;  4 ) month="Apr";; 
         5 ) month="May";;  6 ) month="Jun";; 
         7 ) month="Jul";;  8 ) month="Aug";; 
         9 ) month="Sep";;  10) month="Oct";; 
         11) month="Nov";;  12) month="Dec";;
         * )echo "$0: Unknown numeric month value $1" >&2; exit 1
     esac
     return 0
 }
 
 ### 腳本的主要部分
 
 if [ $# -ne 3 ]; then
     echo "Usage: $0 month day year" >&2
     echo "Typical input formats are August 3 1962 and 8 3 2002" >&2
     exit 1
 fi
 
 if [ $3 -lt 99 ] || [ $3 -gt 9999 ]; then
     echo "$0: expected four-digit year value." >&2; exit 1
 fi
 
 if [ -z $(echo $1 | sed 's/[[:digit:]]//g') ]; then
     monthnoToName $1
 else
     # 正常化開頭的3個字母,第一個大寫,剩下的小寫
     month="$(echo $1 | cut -c1 | tr '[:lower:]' '[:upper:]')"
     month="$month$(echo $1 | cut -c2-3 | tr '[:upper:]' '[:lower:]')"
 fi
 
 echo $month $2 $3
 
 exit 0

腳本如何工做
   注意第3個條件語句: shell

if [ -z $(echo $1 | sed 's/[[:digit:]]//g') ]; then

   它去掉了全部的數字,而後使用-z來測試看看結果是否是爲空。若是結果爲空,第一個輸入域確定是一個或多個數字,因此調用函數monthnoToName後將它映射到了一個月份的名字上。若是不爲空,經過2個子shell轉義序列(即由$符號和左右圓括號括起來的序列,這樣的目的是調用封裝的命令,而後將輸出替換掉),一個由cut和tr組成的管道就會用來生成月份。第一個序列僅僅是提取了第一個字符,而後用tr命令將它大寫化。(注:序列echo $1 | cut -c1也
能夠寫成${1%${1#?}}。)第二個序列提取了第2和第3個字符,而後將它們小寫化。 函數

   運行腳本:
   爲了確保對未來包含了normdata功能的腳本最大的適應性,這個腳本被設計成能夠在命令行接受3個域的輸入。若是你僅僅是想要交互式的使用這個腳本,相比之下,你要提示用戶是3個域,不過這樣的話,要是想從別的腳本調用normdate的話就不大方便了。 測試

   結果:
   這個腳本完成了咱們所指望的:只要日期格式相對簡單點,就能夠將它正常化,(已知的月份名字,月份的值在1-12之間,還有一個4個數字的年份)。好比: spa

結果
1 ./normdate.sh 8 3 62 2 ./normdate.sh: expected four-digit year value. 3 ./normdate.sh 8 3 1962 4 Aug 3 1962 5 ./normdate.sh AUGust 3 1962 6 Aug 3 1962

   延伸閱讀:
   在你由於本身能夠添加不少的擴展到這個腳本中而變得太興奮以前,能夠看看腳本7,它使用了normdate來正確話輸入的日期。無論怎樣,你如今就能夠作的一個改動是,立刻增長下面的一小段代碼到腳本的開頭測試部分,你的腳本就能夠接受形式爲MM/DD/YYYY或MM-DD-YYYY格式的日期了: 命令行

1 if [ $# -eq 1 ]; then 2 set -- $(echo $1 | sed 's/[\/\-]/ /g') 3 fi

測試下: 設計

1 ./normdate.sh March-11-1911 2 Mar 11 1911 3 ./normdate.sh 8/3/1962 4 Aug 3 1962

最後的腳本是: code

完整的normdate.sh
 #!/bin/sh
 
 monthToName()
 {
     case $1 in
         1 ) month="Jan";;  2 ) month="Feb";; 
         3 ) month="Mar";;  4 ) month="Apr";; 
         5 ) month="May";;  6 ) month="Jun";; 
         7 ) month="Jul";;  8 ) month="Aug";; 
         9 ) month="Sep";;  10) month="Oct";; 
         11) month="Nov";;  12) month="Dec";;
         * )echo "$0: Unknown numeric month value $1" >&2; exit 1
     esac
     return 0
 }
 
 if [ $# -eq 1 ]; then
     set -- $(echo $1 | sed 's/[\/\-]/ /g')
 fi
 
 if [ $# -ne 3 ]; then
     echo "Usage: $0 month day year" >&2
     echo "Typical input formats are August 3 1962 and 8 3 2002" >&2
     exit 1
 fi
 
 if [ $3 -lt 99 ] || [ $3 -gt 9999 ]; then
     echo "$0: expected four-digit year value." >&2; exit 1
 fi
 
 if [ -z $(echo $1 | sed 's/[[:digit:]]//g') ]; then
     monthToName $1
 else
     month="$(echo $1 | cut -c1 | tr '[:lower:]' '[:upper:]')"
     month="$month$(echo $1 | cut -c2-3 | tr '[:upper:]' '[:lower:]')"
 fi
 
 echo $month $2 $3
 
 exit 0
相關文章
相關標籤/搜索