气象数据处理脚本篇(二):批处理

      接着上一篇的问题继续讨论,现有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文件处理的特殊要求。
 
 
 





posted on 2012-06-17 13:14  Parallel Life  阅读(1047)  评论(0编辑  收藏  举报

导航

友荐云推荐