第一章: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
相关文章
相关标签/搜索