登录后查看更多精彩内容~
您需要 登录 才可以下载或查看,没有帐号?立即注册
x
本帖最后由 雪花纷飞 于 2012-6-17 13:00 编辑
接着上一篇的问题继续讨论,现有2011年全年数据,要求提取2011年全年数据中date和uwind两列,并按时间顺序放入同一文件uwind_2011.txt中。数据格式如下图所示:
中心思想:要想实现对数据批处理,关键在于对文件名做文章。
思路1:如果提供的数据名很有规律,如以上文件名wind_yyyy-mm-dd.txt,很自然的想到用三个变量分别代表year、month和day。然后用一个三重循环就可以搞定了。不过由于一个月天数可能是30 or 31天(二月份是28 or 29天),需要判断比较麻烦。
- #! /bin/bash
- for year in 2011
- do
- for month in $(seq -w 1 12)
- do
- case $month in
- 01|03|05|07|08|10|12)
- for day in $(seq -w 1 31)
- do
- filename=wind_$year-$month-$day.txt
- sed '1,7d' $filename | awk '{print $2,$3} >>uwind_2011.txt
- done
- ;;
- 04|06|09|11)
- for day in $(seq -w 1 30)
- do
- filename=wind_$year-$month-$day.txt
- sed '1,7d' $filename | awk '{print $2,$3} >>uwind_2011.txt
- done
- ;;
- 02)
- for day in $(seq -w 1 28)
- do
- filename=wind_$year-$month-$day.txt
- sed '1,7d' $filename | awk '{print $2,$3} >>uwind_2011.txt
- done
- ;;
- esac
- done
- done
复制代码
解释:外两层for语句是对year和month循环,seq -w 1 12语句保证输出一个01,02,…,12月份顺序序列。case语句类似于C语言中的switch case结构,判断每月有多少天。其中2月份没有讨论闰年还是平年(因为已经知道2011是平年了,但可以加上判断语句)。最内层对day循环,给文件名赋值,处理数据,注意这里用的是追加符>>使得数据保存在同一文件里。
这个方法适用于有规律日期作为文件名的数据,以上例子恰好举了一年时间,如果是2011-3-15到2012-9-17的数据,只需在最内层循环加上判断语句即可。
思路2:对于以日期为文件名的文件,我们可以借助linux中date命令来解决问题。
首先简单介绍下date语法,详细介绍google或man date。
常用格式:date [-d datestr] [+ displayFormat]
选项含义:-d datestr 显示由datestr描述的日期
+ displayFormat 控制日期输出格式
常用时间标记:
%Y 完整年份(如2012)
%y 年份后两位数字(如89)
%m 月份 (01..12)
%d 日(01..31) % s 从1970年1月1日00:00:00到目前经历的秒数
- #! /bin/bash
- #start&end date formate should be yyyymmdd
- start_date=20110101
- end_date=20111231
- #transfer date into seconds and count num of days between s&e
- start_date_insec=$(date -d "$start_date" +%s)
- end_date_insec=$(date -d "$end_date" +%s)count_day=$[($end_date_insec-$start_date_insec)/(24*3600)+1]
- for((i=1;i<$count_day;i++))
- do
- dt=$(date +%Y-%m-%d -d "$start_date +$i days")
- filename=wind_$dt.txt
- sed '1,7d' $filename | awk '{print $2,$3} >>uwind_2011.txt
- done
复制代码
解释:这里利用了date命令中设置指定日期向后N天的技巧, date -d "$KNOW_DATE +N days" +%Y%m%d。
首先将开始日期和截止日期转换成从1970年1月1日00:00:00到目前时间的秒数。两者相减除以一天时间的秒数再加1就是要处理的天数。这样转换可以忽略平年和闰年、每月天数的区别。比第一种方法更具有一般性。
思路3:通过ls列出数据所在目录下所有文件名(该目录最好只放置要处理的数据),将ls输出结果写入到一个文件中,将文件名赋给for循环中一个变量,实现循环处理。
- #! /bin/bash
- #脚本与数据data放在同级目录下
- ls ./data/*.txt > ./data/filename.txt
- for fname in $(cat ./data/filename.txt)
- do
- sed '1,7d' $fname | awk '{print $2,$3}' >> uwind_2011.txt
- done
复制代码
解释:此方法更具一般性,不需要文件名按一定规则写,也不关心文件名是用英文还是中文,有没有规律。在英文Linux环境下,中文文件名会变成乱码,无法在脚本中输入中文名进行处理。而此方法则可用于中文文件名数据,如"海浪数据001.txt"这样的数据。
上面说并不关心文件名有没有规律,针对本例处理要求还是需要ls输出文件名是按时间顺序排列的。实际上ls列出数据目录下文件顺序确实是以时间顺序排列的,这可以通过查看filename.txt验证。
以上通过三种方法对txt文件进行了批处理,中心思想是实现对文件名的循环处理。而且越往下的方法越具有一般性。这两篇都是对txt文件的处理,下一篇则讨论下CSV文件处理的特殊要求。
|