zoukankan      html  css  js  c++  java
  • Linux日志分割脚本

    该脚本的功能是定时分割日志文件

    #!/usr/bin/env bash
    
    #定时分割清理日志文件
    
    #usage="Usage: logrotate (start|stop) file (line|size)"
    #usage="-e Usage: logrotate start file (line|size) or logrotate stop"
    usage="-e Usage: ${PROGRAM} { start file (line|size) | stop | restart file (line|size) | status | version | help }"
    
    #获取该文件的名称
    declare -r PROGRAM="$(basename "$0")"
    
    #解析参数
    # get arguments
    startStop=$1
    shift
    logfile=$1
    shift
    lineSize=$1
    shift
    #echo $startStop
    #echo "logfile: $logfile"
    
    #设置心跳,即多长时间执行一次,单位s
    HEARTBEAT=${HEARTBEAT:-$[1*60*60]}
    #HEARTBEAT=30
    #echo $HEARTBEAT
    
    #日志保存天数
    SAVE_DAYS=${SAVE_DAYS:-15}
    
    function get_time(){
      #获取今天日期
      TODAY_DATE=$(date +%Y%m%d)
      #echo $TODAY_DATE
    
      #获取 $SAVE_DAYS 天前的日期
      #EARLY_DATE=`date +%Y%m%d --date="-1 day"`
      EARLY_DATE=$(date +%Y%m%d --date="-${SAVE_DAYS} day")
      #echo $EARLY_DATE
    
      #获取当前时间
      cur_time=$(date "+%Y%m%d%H%M%S")
    }
    
    #清理过期日志文件
    function delete_expired_logfile() {
      logfileLength=`echo ${FILEPrefix} |wc -L`
      let logfileLength=$logfileLength+24
      #echo $logfileLength
      
      #遍历符合表达式的文件
      for logfiles in `ls ${FILEDIR} | grep -o -E ${FILEPrefix}_'[0-9]*'_'[0-9]*'.log`
      do
        #echo $logfiles
        logfileLength2=`echo ${logfiles} |wc -L`
        #如果文件长度等于规定的长度,
        if [ $logfileLength2 -eq $logfileLength ] ; then
          #获取该日志文件的日期
          logDate=${logfiles:6:8}
          if [ $logDate -lt $EARLY_DATE ] ; then
            rm -rf ${FILEDIR}/$logfiles
          fi
        fi
      done
    }
    
    #获取日志目录与日志名
    function get_logname_info() {
      #logfile=/home/user/file/out.log
      #已知文件,获取文件名,该方式是从左开始最大化匹配到字符"/",然后截掉左边内容(包括字符"/"),返回余下右侧部分。
      FILENAME=${logfile##*/}
      #echo "filename: $FILENAME"
      
      #判断$logfile是否包含"/"
      #echo "$logfile" |grep -q "/"
      #if [ $? -eq 0 ] ; then
      if [[ $logfile =~ "/" ]] ; then
        #已知文件,获取文件路径,该方式是从右开始第一次匹配到字符"/",然后截掉右边内容(包括字符"/"),返回余下左侧部分。
        FILEDIR=${logfile%/*}
      else
        FILEDIR="."
      fi
    
      #echo "filedir: $FILEDIR"
    
      #获取文件名前缀
      FILEPrefix=${FILENAME%.*}
      #echo "filePrefix: $FILEPrefix"
    
      #判断$FILENAME是否包含"."
      if [[ $FILENAME =~ "." ]] ; then
        #获取文件名后缀
        FILESuffix=${FILENAME##*.}
      else
        FILESuffix=""
      fi
      #echo "fileSuffix: $FILESuffix"
    
      #LOG_DIR="/usr/local/nginx/logs/"
      #echo $LOG_DIR
    }
    
    ###################################
    #(函数)判断程序是否已启动
    #
    #说明:
    #使用JDK自带的JPS命令及grep命令组合,准确查找pid
    #jps 加 l 参数,表示显示java的完整包路径
    #使用awk,分割出pid ($1部分),及Java程序名称($2部分)
    ###################################
    #初始化psid变量(全局)
    psid=0
    
    function checkpid() {
       javaps=`ps -ef | grep $PROGRAM | grep -v "grep"`
    
       if [ -n "$javaps" ]; then
          psid=`echo $javaps | awk '{print $2}'`
       else
          psid=0
       fi
    }
    
    ###################################
    #(函数)启动程序
    #
    #说明:
    #1. 首先调用checkpid函数,刷新$psid全局变量
    #2. 如果程序已经启动($psid不等于0),则提示程序已启动
    #3. 如果程序没有被启动,则执行启动命令行
    #4. 启动命令执行后,再次调用checkpid函数
    #5. 如果步骤4的结果能够确认程序的pid,则打印[OK],否则打印[Failed]
    #注意:echo -n 表示打印字符后,不换行
    #注意: "nohup 某命令 >/dev/null 2>&1 &" 的用法
    ###################################
    function do_start() {
      echo -n "Starting $PROGRAM ..."
      checkpid
      echo -n "(pid=$psid) "
      if [ $psid -ne 0 ]; then
        echo "[OK]"
        if [[ $lineSize == "line" ]] || [[ $lineSize == "size" ]] ; then
          while true
          do
            get_time
            delete_expired_logfile
            case "${lineSize:-}" in
              line)
                #divide_file_by_line
                divide_file_by_line2
                ;;
    
              size)
                divide_file_by_size
                ;;
    
            esac
          
            sleep ${HEARTBEAT}
          done
        else
          echo "Usage: logrotate start file (line|size)"
        fi
      else
        echo "[Failed]"
      fi
    }
    
    ###################################
    #(函数)停止程序
    #
    #说明:
    #1. 首先调用checkpid函数,刷新$psid全局变量
    #2. 如果程序已经启动($psid不等于0),则开始执行停止,否则,提示程序未运行
    #3. 使用kill -9 pid命令进行强制杀死进程
    #4. 执行kill命令行紧接其后,马上查看上一句命令的返回值: $?
    #5. 如果步骤4的结果$?等于0,则打印[OK],否则打印[Failed]
    #6. 为了防止java程序被启动多次,这里增加反复检查进程,反复杀死的处理(递归调用stop)。
    #注意:echo -n 表示打印字符后,不换行
    #注意: 在shell编程中,"$?" 表示上一句命令或者一个函数的返回值
    ###################################
    function do_stop() {
      checkpid
    
      if [ $psid -ne 0 ]; then
        echo -n "Stopping $PROGRAM ...(pid=$psid) "
        kill -9 $psid
        if [ $? -eq 0 ]; then
          echo "[OK]"
        else
          echo "[Failed]"
        fi
    
        checkpid
        if [ $psid -ne 0 ]; then
          stop
        fi
      else
        echo "================================"
        echo "warn: $PROGRAM is not running"
        echo "================================"
      fi
    }
    
    #copy文件
    function copy_logfile() {
      logfile_bak=${logfile}.bak
      #echo ${logfile_bak}
      cp -rf $logfile ${logfile_bak}
      #filename_bak=${FILENAME}.bak
      #echo ${FILENAME}
      #echo ${filename_bak}
      #cp -rf ${FILEDIR}/${FILENAME} ${FILEDIR}/${filename_bak}
    }
    
    #设置划分文件的行数
    LINE_NUM=${LINE_NUM:-30000}
    #LINE_NUM=${LINE_NUM:-3}
    #echo $LINE_NUM
    #按照固定行数分割文件
    function divide_file_by_line() {
      #get_time
    
      #获取日志文件的行数
      #line=`cat $logfile | wc -l`
      line=`sed -n '$=' $logfile`
      #echo $line
      startLine=1
      #endLine=$line
      i=0
      # 如果line > LINE_NUM,则进行划分, (-gt > , -lt <, )
      #while [ ${endLine} -gt 0 ]
      while [ ${startLine} -lt ${line} ]
      do
        #startLine=1
        let endLine=$startLine+$LINE_NUM-1
        num=`printf "%04d
    " $i`
    
        #sed -n "${startLine},${endLine} p;q" $logfile >result_${cur_time}.txt
        #将 $logfile 文件的从${startLine}到${LINE_NUM}行的数据写到 文件
        #sed -n "${startLine},${LINE_NUM} p" $logfile >${FILEPrefix}_${cur_time}_${num}.log
        sed -n "${startLine},${endLine} p" $logfile >${FILEDIR}/${FILEPrefix}_${cur_time}_${num}.log
        #删除指定的行
        #sed -i "${startLine},${LINE_NUM} d" $logfile
        #let endLine=${endLine}-${LINE_NUM}
        let startLine=$startLine+$LINE_NUM
        let i=$i+1
        #sleep 1s
      done
      #清空文件内容,因为日志文件实时更新,所以不能清空
      #echo "" > $logfile
      #删除指定的行
      sed -i "1,${line} d" $logfile
    }
    
    #按照固定行数分割文件
    function divide_file_by_line2() {
      #get_time
    
      #获取日志文件的行数
      line=`cat $logfile | wc -l`
      #line=`sed -n '$=' $logfile`
    
      # 以行为单位划分文件,-l行数,将urls.txt文件按2000行一个文件分割为多个文件;-d添加数字后缀,比如00,01,02;-a 2表示用两位数据来顺序命名;url_定义分割后的文件名前缀。
      # split urls.txt -l 2000 -d -a 2 url_
      split $logfile -l ${LINE_NUM} -d -a 4 "${FILEDIR}/${FILEPrefix}_${cur_time}_"
      #ls|grep tmp_|xargs -n1 -i{} mv {} {}.txt,意思是先查找tmp_开头的文件,然后逐个重命名为.txt
      ls ${FILEDIR} |grep "${FILEPrefix}_${cur_time}_"|xargs -n1 -i{} mv ${FILEDIR}/{} ${FILEDIR}/{}.log
      #rename_logfile
    
      #清空文件内容,因为日志文件实时更新,所以不能清空
      #echo "" > $logfile
      #删除指定的行
      sed -i "1,${line} d" $logfile
    }
    
    #设置划分文件的大小(单位MB)(1MB=1*1024KB=1*1024*1024B=1*1024*1024*8b)
    #转换成KB
    #SIZE=${SIZE:-$[32*1024]}
    SIZE=${SIZE:-32}
    #SIZE=5
    #echo $SIZE
    #按照文件大小,分割文件
    function divide_file_by_size() {
      #get_time
    
      #获取日志文件的行数
      line=`cat ${logfile} | wc -l`
      
      #按文件大小划分
      # 以文件大小为单位划分文件,-b, --bytes=SIZE:对file进行切分,每个小文件大小为SIZE,可以指定单位b,k,m;-d添加数字后缀,比如00,01,02;-a 2表示用两位数据来顺序命名;url_定义分割后的文件名前缀。
      # split urls.txt -b 500k -d -a 2 url_
      split $logfile -b ${SIZE}m -d -a 4 "${FILEDIR}/${FILEPrefix}_${cur_time}_"
      #ls|grep tmp_|xargs -n1 -i{} mv {} {}.txt,意思是先查找tmp_开头的文件,然后逐个重命名为.txt
      ls ${FILEDIR}|grep "${FILEPrefix}_${cur_time}_"|xargs -n1 -i{} mv ${FILEDIR}/{} ${FILEDIR}/{}.log
      #rename_logfile
    
      #删除指定的行
      sed -i "1,${line} d" $logfile
    }
    
    #重命名日志文件
    function rename_logfile() {
      #加.log后缀
      for logfiles in `ls ${FILEDIR} | grep "${FILEPrefix}_${cur_time}_"`
      do
        # 拼接成文件名
        logfilename="${logfiles}.log"
        # 更改文件名
        mv ${FILEDIR}/$logfiles ${FILEDIR}/$logfilename
      done
    }
    
    function do_version() {
      echo "$PROGRAM version "1.0""
    }
    
    ###################################
    #(函数)检查程序运行状态
    #
    #说明:
    #1. 首先调用checkpid函数,刷新$psid全局变量
    #2. 如果程序已经启动($psid不等于0),则提示正在运行并表示出pid
    #3. 否则,提示程序未运行
    ###################################
    status() {
       checkpid
    
       if [ $psid -ne 0 ];  then
          echo "$PROGRAM is running! (pid=$psid)"
       else
          echo "$PROGRAM is not running"
       fi
    }
    
    #主函数
    function main() {
      get_logname_info
    
      case "${startStop:-}" in
        start)
          if [ ${logfile:-} ] ; then
            do_start
          else
            echo "Usage: logrotate start file (line|size)"
          fi
          ;;
    
        stop)
          do_stop
          ;;
    
        restart)
          do_stop
          if [ ${logfile:-} ] ; then
            do_start
          else
            echo "Usage: logrotate restart file (line|size)"
          fi
          ;;
    
        status)
          do_status
          ;;
    
        version|--version|-v)
          do_version
          ;;
    
        help|--help|-help)
          echo $usage #"Usage: ${PROGRAM} { start | stop | restart | status | version | help }"
          ;;
    
        *)
          echo >&2 $usage #"Usage: ${PROGRAM} { start | stop | restart | status | version | help }"
          exit 1
          ;;
      esac
    }
    
    #运行
    main "$@"
  • 相关阅读:
    制作openresty的docker镜像 + nginx笔记 调试rewrite和location Nginx 学习笔记
    C# winform在WebBrowser下获取完整的Cookies(包括含HTTPOnly属性的)
    vscode代码切换大小写的教程
    C#中的Guid
    .NET Framework 版本和依赖关系
    将 Excel 数据导入 SQL Server数据库
    sqlserver各版本的介绍对比
    使用 Visual Studio Code 创建并运行 Transact SQL 脚本
    SQL转Linq工具的使用——Linqer 4.6
    对象之间的映射(AutoMapper集成)
  • 原文地址:https://www.cnblogs.com/zhangchao0515/p/9797083.html
Copyright © 2011-2022 走看看