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\n" $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 "$@"