There is log rotate in Linux system. It can cut and archive old logs according to our expectation. It can also compress the cut logs and define the retention time of old logs.
The requirement of this case is to use shell script to implement logrotate-like functions. Specific requirements are as follows:
1) The log path to be processed: / data/logs/1.log
2) Cut logs at 0:0 every day
3) Keep the old log for one week
4) The name of the archived log is: 1.log.1, 1.log.2,..., 1.log.7
5) Assuming that new logs can be automatically generated after archiving
Knowledge Point 1: logrotate
First of all, this case script will not refer to this part of the knowledge points, here is only a brief introduction, the following through a configuration to explain its meaning.
/var/log/messages { //Log Path rotate 5 //Keep 5 archived logs weekly //Cut once a week postrotate //After defining the cutting day, the instructions to be executed /usr/bin/killall -HUP syslogd //Overload the syslogd service, which generates a new / var/log/messages file endscript //This is the end of executing shell commands. } "/var/log/httpd/access.log" /var/log/httpd/error.log { //The path of writing multiple logs at the same time rotate 5 mail www@my.org //Send the archived log to the mailbox size 100k //Cutting begins when the log file reaches 100k sharedscripts //For all logs defined on the first line, the following shell command (/ usr/bin/killall - HUP httpd) runs only once, not once for every log cut. postrotate /usr/bin/killall -HUP httpd endscript } /var/log/news/* { //Support * Wired monthly //Cut logs once a month rotate 2 //Keep 2 archive logs olddir /var/log/news/old //Save the cut logs under this directory missingok //If the log file is lost, no error is reported. postrotate kill -HUP 'cat /var/run/inn.pid' endscript nocompress //The archived log is uncompressed, and its relative parameter is compress. }
Knowledge Point 2: exit, break, and continue in the shell
1)exit
If you use exit in shell scripts, you exit the current script directly, and all subsequent instructions of exit are no longer executed. The example script exit.sh:
#!/bin/bash for i in `seq 1 5` do echo $i if [ $i -eq 3 ] then exit 1 fi echo $i done echo aaaaa
The script is executed as follows:
# sh exit.sh 1 1 2 2 3
exit can be followed by a number indicating the return value of the script. After executing the script, echo $? Can be executed to print the return value of the script.
# echo $? 1
2)break
In a shell script loop, break can be used to jump out of the loop body. The sample script break.sh:
#!/bin/bash for i in `seq 1 5` do echo $i if [ $i -eq 3 ] then break fi echo $i done echo aaaaa
The script is executed as follows:
# sh break.sh 1 1 2 2 3 aaaaa
Explanation: When $i is 3, the break instruction is encountered, and the whole loop is jumped out, thus the echo aaaaa instruction is executed.
3)continue
Similar to break, the function of continue is to end this cycle and continue the next one without ending the whole cycle. The sample script continues.sh:
#!/bin/bash for i in `seq 1 5` do echo $i if [ $i -eq 3 ] then continue fi echo $i done echo aaaaa
The script is executed as follows:
# sh continue.sh 1 1 2 2 3 4 4 5 5 aaaaa
Explanation: When $i=3, you encounter a continue instruction, and then end the cycle. That is, the instruction echo $i after continue is no longer executed, and continue the subsequent cycle, i=4.
Reference script for this case
#!/bin/bash #Log cutting file, cut by day, 1.log changes 1.log.1, 1.log.1 changes 1.log.2,... #Authors: #Date: logdir=/data/logs/ #Define functions, delete if a file exists function e_df() { if [ -f $1 ] then rm -f $1 fi } cd $logdir #From 7 to 2, traverse the cycle in turn for i in `seq 7 -1 2` do #$i2 is 1 less than $i i2=$[$i-1] #First, determine whether 1.log.7 exists or not, and delete it if it exists. e_df 1.log.$i #When 1.log.6 exists, then 1.log.6 is renamed 1.log.7, and so on. if [ -f 1.log.$i2 ] then mv 1.log.$i2 1.log.$i fi done #Because 1.log has no suffix after it, so we can't go to the for loop above, we can only take it out to deal with it separately. e_df 1.log.1 mv 1.log 1.log.1 ##Explanation: After the script is written, it is put into the task plan and executed at 0:0 every day.
Demand expansion
Now the requirement is that the logs are cut by size. For example, when the logs are larger than or equal to 100M, they need to be processed. The processed logs need to be compressed and delayed for one day, i.e. 1.log.1 does not need to be compressed. Others need to be compressed.
#!/bin/bash #Log cutting and archiving, according to the log size cut (100M), 1.log changed 1.log.1, 1.log.1 changed 1.log.2,... #Authors: #Date: logdir=/data/logs/ #Technology 1.log size size=`du -sk $logdir/1.log |awk '{print $1}` #If 1.log is less than 100M, exit the script if [ $size -lt 10240 ] then exit 0 fi #Define functions, delete if a file exists function e_df() { if [ -f $1 ] then rm -f $1 fi } cd $logdir #If 1.log.1 exists, first compress it to 1.log.1.gz so that the following for loop does not go wrong if [ -f 1.log.1 ] then gzip 1.log.1 fi #Since 1.log.1 has been compressed to 1.log.gz, it is possible to rename 1.log.1 directly. mv 1.log 1.log.1 #From 7 to 2, reverse cycle for i in `seq 7 -1 2` do #$i2 is 1 less than $i i2=$[$i-1] #First, we judge whether 1.log.7.gz exists or not, and delete it if it exists. e_df 1.log.$i.gz #When 1.log.6.gz exists, 1.log.6.gz is renamed 1.log.7.gz, and so on. if [ -f 1.log.$i2.gz ] then mv 1.log.$i2.gz 1.log.$i.gz fi done ##Note: Since we need to cut the log size, it needs to be executed every minute after the script is written.