代码改变世界

老大让我学Linux之练笔作业:过时文件删除脚本,日志监控程序

2011-07-29 16:29  Aga.J  阅读(769)  评论(0编辑  收藏  举报

练笔作业1:

  要求使用脚本将某个目录下前两天的文件删除

实现:

  #!/bin/bash

  threshold=$(date --date='2 days ago'   +%Y-%m-%d)
  directory=testDir

  cd /$directory

  ls -l | awk '{v0="rm -r"; v1=$8; if ($6!="" && $6<"'"$threshold"'") {print "delete ",$8;system(v0" "v1)}}'

  cd ../

问题:这个鬼实现那是相当垃圾啊,为了锻炼下自己,我坚决不看网络上别人的实现,自己就拿自己前几天学的东西,也就是前几篇内介绍的东西来做这个东西了,发现,没有静下心来学习linux,心里急着参加到大家的linux开发中而学习linux是没有好效果了,这一点从我对awk的使用过程中出现好多问题可以看出,最后老大给我他的解决方法:

#!/bin/sh

CONTROL_FILE_DIR=/data/tmp/

BACK_DAYS=2

find ${CONTROL_FILE_DIR} –maxdepth 1 –mindepth 1 –mtime +${BACK_DAYS} –print –exec rm –f {} \;

-0 - 就这么简单,我惊讶的发现竟然有find这个指令啊,还要继续补补,然后再仔细深入…最后老大问如果要定时删除怎么办,用crontab的方式可以实现

 

练笔作业2:

  要求写一个日志监控程序,监控某个文本文件的新纪录的到来,然后从这条纪录里面提取出相关字段的值,然后打印出来,加个小要求,自己写个自动插入纪录的程序

实现:

0 桩模块
  数据自动更新,使用c标准库函数fopen打开目标文件后,进行纪录插入操作,注意每次插入后要进行fflush,将数据从缓冲区内刷到磁盘。

#include<stdio.h>
#include<unistd.h>

#define animationOn 1

void main()
{
  FILE *fd=fopen("stat.log","at+");
  if ( fd==NULL)
  {
    printf("%s","error");
  }
  else
  {  
   while(1)
   {
   sleep(3);                                 //update data every 3 seconds
   fputs(“A:1234 B:4567 C:8632\n",fd);
   fflush(fd);
   printf("addNewRecord\n");
   }
  }
}

1 监控模块
  监控新数据的到来,一开始的想法是使用缓冲区的方式,即读和写的操作间建立一条管道,类似于普通网络编程下服务器接收客户端的信息那样,服务器不断询问客户端stream是否有新的数据到来一样,但是这里我们要求的读写需要实际写入到文件中,而且似乎找不到文件的共享管道的东东(知道的同学可以告诉我),我试过fopen文件然后对得到的文件流进行不断的fgets,但是这行不通,原因如前面所说的那样,fopen后得到的文件流已经在打开文件的那时就固定了内容(其实就是FILE结构),并不是一个动态的可增长的并且连接到写操作的stream。还有一种方法是循环监测目标文件的大小变化或访问时间的变化,一旦有变化就重新打开文件并从上次已经读取的位置开始读取后面新的数据,因为考虑到想目标文本可能被很频繁进行插入操作,这样一来,要做到实时更新就要不断的打开文件关闭文件,所以也只是稍微考虑了下这种想法。

  那么还有什么方式呢?记得在学指令的时候学到一个tail指令,他有个功能很特殊,使用tail -f可以自动显示最新加入的数据,那可以在程序里使用这个指令吗?网上搜了一下,可以!我们使用popen并加入tail指令,由于有了tail指令的特性,我们便可以不停的进行fgets来获取最新的数据行并做处理。 (经过一轮google和tail源码阅读,我发现其实tail -f也会监控目标文件的属性来判断是否阅读新内容,在高点的内核版本上还支持文件属性修改的notify机制,这样一来就和前面所忽略的方法类似了。)

  FILE *fd=popen("tail -f -n +1 stat.log","r");   //make use of tail -f
  if ( fd==NULL)
  {
     printf("%s","error");
  }
  else
  {
     char newRecord[recordLength];
     int i=0;
     while(1)
     {
       newRecord[0]='\0';                //clear old content
       if( fgets(newRecord,recordLength,fd)==NULL )
       {
          sleep(3);                                  //check new record every 3 seconds
       }
       else
      {
         int beginPos=0;
         if(!feof(fd))
         {
           printf(“%s”,newRecord);
         } 
      }
    } 
}

2 数据提取模块
  将新纪录的必要数据进行提取,这里根据记录的文本规则来抽取,每条记录的格式是这样 ABC:123 EDF:456….,所要抽取的就是每个标签后面的数字,基本思路是先设定抽取时的分隔符,然后使用string类的find来找到标签位置,然后就可以进行数据值提取,然后继续使用find,提取值,直到结束,注意这里我在使用find时用的是带有start pos参数的那个find重载函数,这样我们就可以避免对一行记录进行多次的遍历,可以直接在上次找到标签的位置开始进行第二次查找。

string getTargetValue(const string sourceStr,const string matchingStr,const char seperator,int& searchPos)
{
  int firstMatchPos=sourceStr.find(matchingStr,searchPos);
  if(firstMatchPos!=-1)
  {
  int valuePos=firstMatchPos+matchingStr.size();
  int valueCount=0;
  int tempPos=valuePos;
  int sourceSize=sourceStr.size();
  while( sourceStr[tempPos]!=seperator && sourceSize>tempPos && sourceStr[tempPos]!='\n' )
  {
    valueCount++;
    tempPos++;
  }
  return sourceStr.substr(valuePos,valueCount);
  searchPos=tempPos;
  }
  else
  {
    printf("can't find value for %s, please check!\n",matchingStr.data());
    return "";
  }
}

3 数据上报模块(提供接口)
  将新纪录上传,拿到的记录我将它们作为某个对象的一个一个字段,封装到对象中,上报数据时使用的数据就是一个对象。

    /*
         print result!
         this result can be use in the form of:
     (1)report(r);  [recommend]

    */