气象数据处理脚本篇(二):批处理
接着上一篇的问题继续讨论,现有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文件处理的特殊要求。
作者:Parallel Life
出处:http://www.cnblogs.com/Parallel-Life/
同步博客:http://metman.info/
本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接
如有问题,可以通过jiangqingu@gmail.com 联系我,非常感谢。
posted on 2012-06-17 13:14 Parallel Life 阅读(1047) 评论(0) 编辑 收藏 举报