对于shell脚本的开发者来说,数据的资料格式不一致是一个很大的问题,要让它们能够标准化也是一个相当棘手的问题。日期的格式是众多问题中的一个,因为日期的表示方式有许多种,即使我们使用"月日年"的方式来表示,我们也可能有不同的输入方式:月份的部份我们可以输入英文的月份缩写或大写的全名。
基于这个理由,我特別编写一个基本的日期格式程序,这个程序对于你以后的脚本编写会有相当大的帮助。
脚本源代码
#!/bin/sh # normdate -- Normalizes month field in date specification # to three letters, first letter capitalized. A helper # function for Script #7, valid-date. Exits w/ zero if no error.
monthnoToName() { # Sets the variable 'month' to the appropriate value 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 ] ; then echo "$0: expected four-digit year value." >&2; exit 1 fi
if [ -z $(echo $1|sed 's/[[:digit:]]//g') ]; then monthnoToName $1 else # Normalize to first three letters, first upper, rest lowercase 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
工作原理
注意第三个判断式: if [ -z $(echo $1|sed 's/[[:digit:]]//g') ]; then
它会将所有的数字刪除,并且利用 -z 来进行测试结果是不是空白字元,如果是空白字元,表示第一个字必定是数字,那么程序会调用monthnoToName来做查表的动作。接下来的两行会利用cut与tr将月份的字母进行分离及转换。第一行是分离出第一个字元,再利用tr命令将它转换成大写字母(之前提过,以POSIX而言 echo $1|cut -c1 这种写法也可以写成 ${1%${1#?}} )。第二行是将第二及第三个字母转换成小写字母:
month="$(echo $1|cut -c1|tr '[:lower:]' '[:upper:]')" month="$month$(echo $1|cut -c2-3 | tr '[:upper:]' '[:lower:]')"
运行脚本
为了让该脚本normdate在以后能有更大的应用空间,我们把脚本设计成可以在命令列上输入三个栏位的程序。另外,如果你想让此程序更具互动性,你应该要提示使用者输入三个栏位。相比较之下,两者之间似乎是后者较难。
结果
对于这个程序,我们希望它能夠将一个简单的日期(已知的月份名称或月份数字及四位数的年份)变成一个标准的日期格式。举例:
$ normdate 8 3 62 normdate: expected four-digit year value. $ normdate 8 3 1962 Aug 3 1962 $ normdate AUGUST 3 1962 Aug 3 1962
改进与加强
这个脚本有很大的扩充性。另一方面,只要做一点点的修改,我们就可以让这个脚本接受不同的日期格式,例如MM/DD/YYYY或者是MM-DD-YYYY,请将底下的程序代码附加在刚才我们提及的判断式前:
if [ $# -eq 1 ] ; then # try to compensate for / or - formats set -- $(echo $1 | sed 's/[\/\-]/ /g') fi
修改后,我们也可以输入这样的时间格式:
$ normdate March-11-1911 Mar 11 1911 $ normdate 8/3/1962 Aug 3 1962 |