分享几个实用脚本

Shell面试题及企业运维实战案

1、批量生成随机字符文件名:

要求:使用for循环在/oldboy目录下批量创建10个html文件,其中每个文件需要包含10个随机小写字母加固定字符串oldboy
问题分析:本题考查的第一个知识点就是生成10个随机小写字母,这里采用openssl命令的方法来实现。

openssl  rand  -base64  40 | sed  ‘s#[^a-z]##g’ | cut -c 2-11
  //利用openssl生成40个随机数,并用sed将非小写字符删除,然后利用cut取出其中10位

参考脚本

[root@oldboy scripts]# cat randnum.sh
#!/bin/sh
Path = /oldboy                               //定义生成文件的路径
[ -d "$Path" ] || mkdir -p $Path             //如果定义的路径不存在则创建。
for n in `seq 10`
do
random = $(openssl rand -base64 40 | sed ‘s#[^a-z]##g’ | cut -c 2-11) 
                                      //将10位随机字符赋值给变量
touch $Path/${random}_oldboy.html        //根据题意生成所需要的文件
done

结果:apquvdpqbk_oldboy.html     bmqiwhfpgv_oldboy.html
      ......

2、批量改名

将上述(第1题)所得文件名中的oldboy字符串全部改成oldgirl(最好用for循环并且将扩展名全部改成大写)

  • 方法1:
[root@oldboy script]# cat chname.sh
#!/bin/bash
Filename = _oldgirl.HTML        //定义替换后的目标字符串。
Dirname = "/oldboy"            //定义操作目录。
cd $Dirname || exit 1          //切换到指定目录下,如果不成功则退出。
for n in `ls`
do
name = $(echo ${n} | awk -F '_' '{print $1}') //定义替换后的目标。
mv $n ${name}${Filename}       //实际mv改名操作命令
done
  • 方法2:
[root@oldboy scripts]# cat chname.sh
#!/bin/bash
Path = "/oldboy"
cd $Path && \
ls | awk -F '_' '{print "mv "$0" "$1"_oldgirl.HTML"}' | bash
  • 方法3:
[root@oldboy script]# rename oldboy.html oldgirl.HTML *.html

3、批量创建5个系统账号(oldboy01-oldboy10),并设置密码(密码为随机数,要求是字符和数字的混合)

#!/bin/bash
. /etc/init.d/functions
user="oldboy"
passfile="/tmp/user.log"
for num in `seq -w 10`
do
   useradd $user$num    //创建用户
   pass="`echo "test$RANDOM" | md5sum | cut -c3-11`"
       //若多次用到随机数,就要将其定义成变量。
   echo "$pass" | passwd --stdin $user$num   //设置密码
   echo -e "user:$user$num\tpasswd:$pass">>$passfile 
      //记录设置的账号和密码信息
done
echo ------this is oldboy trainning class contents------------
cat $passfile

4、扫描网络内存活主机

写一个Shell脚本,判断10.0.0.0/24网络里,当前在线的IP有哪些?
(1)问题分析
判断IP在线最常见的方法就是使用ping命令,其实还有一个不错的命令就是nmap,这个nmap命令有可能需要执行括号内的命令安装(yum install nmap -y)。
(2)参考答案
方法1:并发ping方案

[root@oldboy scripts]# cat alive.sh
#!/bin/bash
CMD="ping -W 2 -c 2"   //定义ping命令及参数
Ip="10.0.0."
for n in $(seq 254)
do
    {
    $CMD $Ip$n &> /dev/null      //对指定Ip实行ping政策。
    if [ $? -eq 0 ];then
        echo "$Ip$n is ok"      //打印提示
    fi
    }&    //Shell的并发检测功能,批量ping,快捷返回结果
done

方法2:nmap方案

#!/bin/bash
CMD = "nmap -sP"
Ip = "10.0.0.0/24"
CMD2 = "namp -sS"
$CMD $Ip | awk '/Nmap scan report for/ {print $NF}'

5、数据库备份:

#!/bin/bash
PATH="/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin:/root/bin"

TARGET_DIR="/data/OA/mysql-backup/"

if [ -z $TARGET_DIR ];then
    echo "相关变量没有设置!"
    exit 100;
fi

MYSQL_HOST="10.6.205.30"
MYSQL_USER="root"
MYSQL_PASSWORD="123456"
MYSQL_CHARACTER="gbk"

DB=$(mysql -h$MYSQL_HOST -u$MYSQL_USER -p$MYSQL_PASSWORD -e "show databases;" 2> /dev/null  |egrep -v "Database|information_schema|mysql|performance_schema")
echo $DB

if [ ! -d ${TARGET_DIR}/`date +%F` ];then
    mkdir -p ${TARGET_DIR}/`date +%F`
fi 

for db in $DB
do
     mysqldump -h$MYSQL_HOST -u$MYSQL_USER -p$MYSQL_PASSWORD --default-character-set=$MYSQL_CHARACTER -x -B $db  > ${TARGET_DIR}/`date +%F`/$db-`date +%F`.sql
done

if [ $? -eq 0 ];then
    tar zcf  ${TARGET_DIR}/`date +%F`.tar.gz   ${TARGET_DIR}/`date +%F`  && rm -rf ${TARGET_DIR}/`date +%F`
    find ${TARGET_DIR}/*  -name "*.tar.gz" -a -mtime +30  -exec rm -f {} \;
fi

6、筛选符合长度的单词

计算变量内容的长度,常见的方法有4种:

[root@oldboy scripts]# char=oldboy
[root@oldboy scripts]# echo $char | wc -L
6
[root@oldboy scripts]# echo ${#char}
6
[root@oldboy scripts]# expr length $char
6
[root@oldboy scripts]# echo $char | awk '{print length($0)}'
6

方法1:通过数组方法来实现

arr = (I am oldboy teacher welcome to oldboy training class)
for ((i=0;i<${#arr[$i]};i++))
do 
   if [ ${#arr[$i]} -lt 6 ]
      then 
        echo "${arr[$i]}"
   fi
done
echo ------------------------
for word in ${arr[*]}
do
   if [ `expr length $word` -lt 6 ];then
        echo $word
   fi
done

本例列出了用两种for循环打印数组元素的方法

方法2:使用for循环列举取值列表法

for word in I am oldboy teacher welcome to oldboy training class
do
  if [ `echo $word | wc -L` -lt 6 ];then
      echo $word
  fi
done


chars = "I am oldboy teacher welcome to oldboy training class"  //定义字符串
for word in $chars
do
   if [ `echo $word | wc -L` -lt 6 ];then
       echo $word
   fi
done

方法3:使用awk循环实现

[root@oldboy scripts]# chars = "I am oldboy teacher welcome to oldboy training class"
[root@oldboy scripts]# echo $chars | awk '{for(i=1;i<=NF;i++) if(length($i)<=6) print $i}'

7、比较两个整数的大

开发Shell脚本,分别实现以脚本传参和read读入的方式比较两个整数的大小。用条件表达式(禁止用if)进行判断并以屏幕输出的方式提醒用户比较的结果。注意:一共是开发两个脚本。再用脚本传参和read读入的方式实现时,需要对变量是否为数字及传参个数是否正确给予提示。

  • 参考答案1:
[root@oldboy scripts]# cat compare.sh
#!/bin/bash
read -p "Pls input two num:" a b   //请求用户输入两个参数,读入后分别赋值给变量a和b。

#no1
[ -z "$a" ]||[ -z "$b" ]&&{//若$a变量长度为0或$b变量长度为0,即任何一个变量为0,则执
                          行命令。
   echo "Pls input two num again." //a或b没值,表示用户输入错误,给出提示。
   exit 1                          //以返回值1退出脚本

}
#no2
expr $a + 10 &>/dev/null  //判断$a是否为整数,不输出任何信息
RETVAL1 = $?   //将返回值赋值给RETVAL1,后面会用这个返回值做判断
expr $b + 10 &>/dev/null   //判断$b是否为整数,不输出任何信息
RETVAL2 = $?   //将返回值赋值给RETVAL2, 后面会用这个返回值做判断
test $RETVAL1 -eq 0 -a $RETVAL2 -eq 0 || {//利用test进行返回值是否为0的判断,如果有一个返回值不为0,则说明有一个变量不为整数,不合要求,打印提示后退出。
     echo "Pls input two "num" again."
     exit 2
}
#no3
[ $a -lt $b ] && {//整数比较,$a是否小于$b。
   echo "$a < $b"
   exit 0
}
#no4
[ $a -eq $b ] && {//整数比较,$a是否等于$b.
   echo "$a < $b"
   exit 0
}
#no5
[ $a -gt $b ] && {//整数比较,$a是否大于$b。
   echo "$a < $b"
   exit 0
}
  • 参考答案2
[root@oldboy scripts]# cat compare.sh
#!/bin/sh
a=$1 //接收脚本的第一个参数$1赋值给a。
b=$2 //接收脚本的第二个参数$2赋值给b。
#no1
[ $# -ne 2 ] && {//传参专用判断手法,判断传参个数是否为2个
    echo "USAGE:$0 NUM1 NUM2" //传参不符合要求,给出用法提示。
    exit 1 //以返回值1退出脚本
}
#no2
expr $a + 10 &>/dev/null  //整数判断
RETVAL1=$?
expr $b + 10 &>/dev/null  //整数判断
RETVAL2=$?
test $RETVAL1 -eq 0 -a $RETVAL2 -eq 0 || {
     echo "Pls input two "num" again."
     exit 2
}
#no3
[ $a -lt $b ] && {
    echo "$a < $b"
    exit 0
}
#no4
[ $a -eq $b ] && {
    echo "$a = $b"
    exit 0
}
#no5 
[ $a -gt $b ] && {
    echo "$a > $b"
    exit 0
}

8、WEB及MySQL服务异常监测

if条件语句实现对Nginx Web服务及MySQL数据库服务是否正常的检测,如果服务未启动,则启动相应的服务。本例同样适用于其他的Web服务和数据库服务。
(1)分析问题
监控Web服务和数据库服务是否异常的常见方法:

  • 端口监控
    1)在服务器本地监控服务端口的常见命令有netstatsslsof
    2)从远端监控服务器本地端口的命令有telnetnmapnc

  • 监控服务进程或进程数
    此方法适合本地服务器,注意,过滤的是进程的名字。命令为:
    ps -ef | grep nginx | wc -l
    ps -ef | grep mysql | wc -l

  • 在客户端模拟用户访问
    使用wgetcurl命令进行测试(如果检测数据库,则需要转为通过web服务器去访问数据库),并对测试结果做三种判断
    1)利用返回值(echo $?)进行判断
    2)获取特殊字符串以进行判断(需要事先开发好程序)
    3)根据HTTP响应header的情况进行判断

  • 登入MySQL数据库判断
    通过MySQL客户端连接数据库,根据返回值或返回内容判断。例如:
    mysql -uroot -poldboy123 -e "select version(); &/dev/null;echo $?"

此外,对端口进程等进行判断时,尽量先通过grep过滤端口和进程特殊标记字符串,然后结合wc将过滤到的结果转成行数再比较,这样相对简单有效,且经过wc -l命令处理之后的结果一定是数字,这样在进行判断就会比较方便。如果单纯的根据具体的列取具体的值判断会很麻烦,如果确实想采用取值判断的方法,那就尽量用字符串比较的语法。
(2)监控MySQL数据库异常
1)MySQL数据库环境准备

[root@oldboy ~]# yum install mysql-server -y
[root@oldboy ~]# /etc/init.d/mysqld start
正在启动 mysqld:            [确定]
[root@oldboy ~]# netstat -lntup | grep mysql
tcp   0   0  0.0.0.0:3306   0.0.0.0:*   LISTEN   2275/mysqld   

2)通过命令行检测数据库服务是否正常,只有先确定命令行是正确的,才能确保将它放到脚本里也是正确的。
首先采用端口监控的方式。在服务器本地监控端口的命令有netstatsslsof,具体实现多种命令的方法如下:

[root@oldboy scripts]# netstat -lnt | grep 3306 | awk -F "[ :]+" '{print $5}' //根据具体的列取值的判断方法,获取列值,然后看看其是否等于3306,不推荐使用这种取值的方法,因为第一取值麻烦;第二如果使用数字比较,当端口不存在时就会报错,而一旦使用了取值判断方法,即使看起来是数字,也要尽量使用字符串进行比较,否则你将掉进坑里,很久都会爬不上来
3306

[root@oldboy scripts]# netstat -lntup | grep 3306 | wc -l  //过滤关键字端口,转成数字,此方法很好
1

[root@oldboy scripts]# netstat -lntup | grep mysql | wc -l  //过滤关键字进程,转成数字,此方法很好
1

[root@oldboy scripts]# ss -lntip | grep mysql | wc -l  //ss类似于netstat命令,参数选项可通用。
1


[root@oldboy scripts]# ss -lntup | grep 3306  wc -l  //ss类似于netstat命令,参数选项可通用
1


[root@oldboy scripts]# lsof -i tcp:3306 | wc -l  //利用lsof检查tcp协议的3306端口
2
  • 从远端监控服务器监控本地端口的命令有telnetnmapnc,这三个命令有可能需要事先安装好才能使用,安装方法为:
[root@oldboy scripts]# yum install telnet nmap nc -y

[root@oldboy scripts]# nmap 127.0.0.1 -p 3306 | grep open | wc -l
//查看远端3306端口是否开通,过滤open关键字,结果返回1,说明有open关键字,表示3306端口是通的。
1

[root@oldboy scripts]# echo -e "\n" | telnet 127.0.0.1 3306 2>/dev/null | grep Connected | wc -l  //telnet是常用来检测远端服务器端口是否通畅的一个好用的命令,在非交互式时需要采用特殊写法才行,过滤的关键字为Connected,返回1,说明有Connected,表示3306端口是通的。
1


[root@oldboy scripts]# nc -w 2 127.0.0.1 3306 &>/dev/null  //nc的命令很强大,这里用来检测端口。根据执行命令的返回值判断端口是否通畅,如果返回0,则表示通畅,-w为超时时间
[root@oldboy scripts]# echo $?
0

本例为了统一IP地址,因此使用的都是同一个Ip,即127.0.0.1,在实际工作中,应该使用服务器的IP来替代。

  • 下面对服务进程或进程数进行监控(适合本地服务器)
[root@oldboy scripts]# ps -ef | grep mysql | grep -v grep | wc -l
3
  • 以下是在客户端模拟用户访问的方式进行监控
    使用wgetcurl命令访问URL地址来测试。根据执行命令的返回值判断成功与否,本例的URL使用了网上的地址,在实际工作中应使用开发人员提供给我们的访问数据库的程序地址。
[root@oldboy scripts]# wget --spider --timeout=10 --tries=2 www.baidu.com &>/dev/null  //在wget后面加url的检测方法,&>/dev/null表示不输出,只看返回值。--spider的意思是模拟爬取,--timeout=10的意思是10秒超时,--tries=2表示不成功,则重试两次。
[root@oldboy scripts]# echo $? //查看命令执行的返回值,0为成功。
0


[root@oldboy scripts]# wget -T 10 -q --spider http://www.baidu.com >&/dev/null  //用法同上,-q表示安静的。
[root@oldboy scripts]# echo $?  //查看命令执行的返回值,0位成功
0


[root@oldboy scripts]# curl -s -o /dev/null http://www.baidu.com //利用curl进行检测,-s为沉默模式,-o /dev/null表示将输出定向到空。
[root@oldboy scripts]# echo $? //查看命令执行的返回值,0为成功。
0

3)、开发监控MySQL数据库的脚本

脚本1:
#!/bin/sh
echo method1------------------------------------------
if [ `netstat -lnt | grep 3306 | awk -F "[ :]+" '{print $5}'` -eq 3306 ]
//这里的判断思路不是很好,最好不要用整数进行比较,因为一旦端口不存在,取值就会为空,进行整数比较会报错。还有不要根据列取具体的值,而是要过滤关键字,通过wc转成行数判断。
    then
        echo "MySQL is Running."
else 
        echo "MySQL is Stopped."
        /etc/init.d/mysqld start
fi

脚本2:
echo method2------------------------------------------
if [ "`netstat -lnt | grep 3306 | awk -F "[ :]+" '{print $5}'`" = "3306" ]
//用字符串的方式进行比较就好多了,避免了脚本1中整数比较的错误发生,但是取值麻烦了一些。
    then
        echo "MySQL is Running."
else
        echo "MySQL is Stopped."
        /etc/init.d/mysqld start
fi

脚本3:
echo method3------------------------------------------
if [ `netstat -lntup | grep mysqld | wc -l` -gt 0 ]
//过滤进程名,转成数字,很优秀的取值判断方法
    then
        echo "MySQl is Running."
else
        echo "MySQL is Stopped."
        /etc/init.d/mysqld start
fi

脚本4:
echo method4--------------------------------------------
if [ `lsof -i tcp:3306 | wc -l` -gt 0 ]
//过滤端口转成数字,很优秀的取值方法
    then
        echo "MySQl is Running."
else 
        echo "Mysql is Stopped."
        /etc/init.d/mysqld start
fi

脚本5:
echo method5---------------------------------------------
[ `rpm -qa namp | wc -l` -lt 1 ] && yum install namp -y &>/dev/null
//防止因nmap没有安装而导致的错误
if [ `nmap 127.0.0.1 -p 3306 2>/dev/null | grep open | wc -l` -gt 0 ]
//远端的端口检查,推荐使用,同理,这里也不需要过滤出open,然后再做字符串比较,转成数字最佳。
    echo "MySQL is Running."
else
    echo "MySQL is Stipped."
    /etc/init.d/mysqld start
fi

脚本6:
echo method6-----------------------------------------------
[ `rpm -qa nc | wc -l` -lt 1 ] && yum install nc -y &>/dev/null
if [ `nc -w 2 127.0.0.1 3306 &>/dev/null&&echo ok | grep ok | wc -l` -gt 0 ] 
//这个判断有点特若别,即nc执行成功,则输出和之后的过滤都没问题,最后转换成数字,思路决定出路。
    then
        echo "MySQL is Running."
else 
        echo "MySQL is Stopped."
        /etc/init.d/mysqld start
fi

脚本7:
echo method7----------------------------------------------
if [ `ps -ef | grep -v grep | grep mysql | wc -l` -gt 0 ]
//传统的过滤进程的方法。grep -v grep是排除此命令本身
    then
        echo "MySQl is Running."
else 
        echo "MySQL is Stopped."
        /etc/init.d/mysqld start
fi

(3)监控Nginx Web服务异常
监控Nginx Web服务异常的方法和监控MySQl数据库一样,也是使用端口、进程或通过wget/curl访问来进行检测。
1)通过命令行检测Nginx服务是否正常,同样只有命令行是正确的,才能确保它放到脚本里也是正确的。
首先采用端口监控的方式。再监控Nginx和监控数据库端口时,除了端口不同,其他的命令方法都是相同的。在服务器本地监控端口的命令有netstat,ss,lsof,如下:

[root@oldboy ~]# netstat -lnp | grep -w 80 | awk -F "[ :]+" '{print $5}'
80

[root@oldboy ~]# netstat -lntup | grep -w 80 | wc -l
1

[root@oldboy ~]# netstat -lntup | grep mysql | wc -l
1

[root@oldboy ~]# ss -lntup | grep -w 80 | wc -l
1

[root@oldboy ~]# ss -lntup | grep mysql | wc -l
1

[root@oldboy ~]# lsof -i tcp:80 | wc -l
3

在远端监控服务器本地端口的命令有telnetnmapnc,如下:

[root@oldboy ~]# nmap 127.0.0.1 -p 80 | grep open | wc -l
1

[root@oldboy ~]# echo -e "\n" | telnet 127.0.0.1 80 2>/dev/null | grep Connected | wc -l
1

[root@oldboy ~]# nc -w 2 127.0.0.1 80 &>/dev/null
[root@oldboy ~]# echo $?
0

对服务器进程或进程数进行监控的方式(适合本地服务器)如下:

[root@oldboy ~]# ps -ef | grep nginx | grep -v grep | wc -l
2

以下是在客户端模拟用户访问的监控方式。先通过wgetcurl命令进行测试。执行wget或curl命令之后,再看返回值($?),为0,则成功。

[root@oldboy ~]# wget --spider --timeout=10 --tries=2 http:127.0.0.1 &>/dev/null
[root@oldboy ~]# echo $?
0

[root@oldboy ~]# wget -T 10 -q --spider http:127.0.0.1 &>/dev/null
[root@oldboy ~]# echo $?
0

[root@oldboy ~]# curl -s -o /dev/null http://127.0.0.1
[root@oldboy ~]# echo $?
0

以下是获取字符串的方式(判断字获取的字符串是否和事先设定的相等)。

[root@oldboy ~]# curl http://127.0.0.1 
//根据指定的返回值判断服务是否正常

以下是根据HTTP相应header的结果进行判断(200、301、302都表示正常)

[root@oldboy ~]# curl -I -s -w "%{http_code}\n" -o /dev/null http://127.0.0.1
200

注:  -I : 仅返回头部信息。
     -s :  slient 减少输出的信息,比如进度
     -w :用于在一次完整且成功的操作后输出指定格式的内容到标准输出(write-out)

3)开发监控Nginx Web服务的脚本,这里同样给出多个参考脚本。

#!/bin/bash
echo http method1-----------------------------------------
if [ "`netstat -lnt | grep 80 | awk -F "[ :]+" '{print $5}'`" = "80" ]
//字符串比较语法,取值太麻烦,不如过滤后转为行数再比较的方法好。
    then 
        echo "Nginx is Running."
else 
        echo "Nginx is Stopped."
        /etc/init.d/nginx start
fi

脚本2:
echo http method2-----------------------------------------
if [ `netstat -lntup | grep nginx | wc -l` -gt 0 ]
//通过检查端口的命令,过滤进程名(比过滤端口好)转成数字后再比较,这是推荐的用法。
    then 
        echo "Nginx is Running."
else 
        echo "Nginx is Stopped."
        /etc/init.d/nginx start
fi

脚本3:
echo http method3------------------------------------------
if [ `lsof -i tcp:80 | wc -l` -gt 0 ]
    then 
        echo "Nginx is Running."
else
        echo "Nginx is Stopped."
        /etc/init.d/nginx start
fi

脚本4:
echo http method4-------------------------------------------
[ `rpm -qa nmap | wc -l ` -lt 1 ] && yum install nmap -y &>/dev/null
if [ `nmap 127.0.0.1 -p 80 2>/dev/null | grep open | wc -l` -gt 0]
//nmap检测方法,优势是从远端进行检查,推荐使用。
    then
        echo "Nginx is Running."
else 
        echo "Nginx is Stopped."
        /etc/init.d/nginx start
fi

脚本5
echo http method5--------------------------------------------
[ `rpm -qa nc | wc -l` -lt 1 ] && yum install nc -y &>/dev/null
if [ `nc -w 2 127.0.0.1 80 &>/dev/null&&echo ok | grep ok | wc -l` -gt 0 ]
    then 
        echo "Nginx is Running."
else
        echo "Nginx is Stopped."
        /etc/init.d/nginx start
fi

脚本6:
echo http method6---------------------------------------------
if [ `ps -ef | grep -v grep | grep nginx | wc -l` -ge 1 ]
//过滤进程方式,排除自身
    then
        echo "Nginx is Running."
else
        echo "Nginx is Stopped."
        /etc/init.d/nginx start
fi

脚本7:
echo http method7---------------------------------------------
if [[ `curl -I -s -o /dev/null -w "%{http_code}\n" http://127.0.0.1` =~[23]0[012] ]]
//获取状态码,然后做正则数字匹配(目标是200、301、302,但实际上多余了几个201、202、300),这是 [[]] 的特殊匹配用法之一。
    then 
        echo "Nginx is Running."
else
        echo "Nginx is Stopped."
        /etc/init.d/nginx start
fi

脚本8:
echo http method8----------------------------------------------
if [ `curl -I http://127.0.0.1 2>/dev/null | head -1 | egrep "200|301|302" | wc -l` -eq 1 ]
//此方法通过扩展的egrep过滤正确的状态码,然后利用wc转成数字,此方法比较优秀,推荐使用。
    then
        echo "Nginx is Running."
else 
        echo "Nginx is Stopped."
        /etc/init.d/nginx start
fi

脚本9:
echo http method9-----------------------------------------------
if [ "`curl -s http://127.0.0.1`" = "自己定义的字符串"]
//根据访问网站URL,将返回的结果和期待的值进行比较,这个方法略麻烦,但是结果最为准确,适用于数据库及更深层次的对网站集群后端各个应用的检测。
    then
        echo "Nginx is Running."
else
        echo "Nginx is Stopped."
fi

9、写一个脚本计算一下linux系统所有进程占用内存的大小的和。

#!/bin/bash
count=0
#这个循环会遍历出每个进程占用的内存大小
for i in `ps -avx | awk '{print $6}' | grep -v 'RSS'`
do
    #将遍历出来的数字进行累加
    count=$[ $count+$i ]
done
#就得到所有进程占用内存大小的和了
echo "$count/kb"


#也可以使用awk一条命令计算
ps -aux | grep -v 'RSS TTY' | awk '{sum=sum+$6};END{print sum}'

10、设计一个简单的脚本,监控远程的一台机器(假设IP为123.23.11.21)的存活状态,当发现宕机时发一封邮件给自己。

#!/bin/bash
ip=123.23.11.21
email="user@example"
while 1
do
    ping -c10 $ip > /dev/null 2>/dev/null
    if [ $? != "0" ]
    then
        #调用一个用于发邮件的脚本
        python /usr/local/sbin/mail.py $email "$ip down" "$ip is down"
    fi
    sleep 30
done

mail.py脚本代码:

#!/usr/bin/env python
#-*- coding: UTF-8 -*-
import os,sys
reload(sys)
sys.setdefaultencoding('utf8')
import getopt
import smtplib
from email.MIMEText import MIMEText
from email.MIMEMultipart import MIMEMultipart
from  subprocess import *
def sendqqmail(username,password,mailfrom,mailto,subject,content):
    # 邮箱的服务地址
    gserver = 'smtp.qq.com'
    gport = 25
    try:
        msg = MIMEText(unicode(content).encode('utf-8'))
        msg['from'] = mailfrom
        msg['to'] = mailto
        msg['Reply-To'] = mailfrom
        msg['Subject'] = subject
        smtp = smtplib.SMTP(gserver, gport)
        smtp.set_debuglevel(0)
        smtp.ehlo()
        smtp.login(username,password)
        smtp.sendmail(mailfrom, mailto, msg.as_string())
        smtp.close()
    except Exception,err:
        print "Send mail failed. Error: %s" % err
def main():
    to=sys.argv[1]
    subject=sys.argv[2]
    content=sys.argv[3]
    #定义QQ邮箱的账号和密码,你需要修改成你自己的账号和密码
    sendqqmail('[email protected]','aaaaaaaaaa','[email protected]',to,subject,content)
if __name__ == "__main__":
    main()

#####脚本使用说明######
#1. 首先定义好脚本中的邮箱账号和密码
#2. 脚本执行命令为:python mail.py 目标邮箱 "邮件主题" "邮件内容"

11、

需求:

  • 找到/123目录下所有后缀名为.txt的文件
  • 批量修改.txt为.txt.bak
  • 把所有.bak文件打包压缩为123.tar.gz
  • 批量还原文件的名字,即把增加的.bak再删除
#!/bin/bash
now=`date +%F_%T`
mkdir /tmp/123_$now
for txt in `ls /123/*.txt`
do
  mv $txt $txt.bak
  for f in $txt
  do
    cp $txt.bak /tmp/123_$now
  done
done

cd /tmp/
tar czf 123.tar.gz 123_$now/

for txt in `ls /123/*.txt.bak`
do
  name=`echo $txt |awk -F '.' '{OFS="."} {print $1,$2}'`
  mv $txt $name
done

12、设计一个shell脚本来备份数据库,首先在本地服务器上保存一份数据,然后再远程拷贝一份,本地保存一周的数据,远程保存一个月。

假定,我们知道mysql root账号的密码,要备份的库为discuz,本地备份目录为/bak/mysql, 远程服务器ip为192.168.123.30,远程提供了一个rsync服务,备份的地址是 192.168.123.30::backup . 写完脚本后,需要加入到cron中,每天凌晨3点执行。

#!/bin/bash
PATH=$PATHi:/usr/local/mysql/bin
week=`date +%w`
today=`date +d`
passwd="123456"
backdir="/data/mysql"
r_backupIP="192.168.123.30::backup"

exec 1>/var/log/mysqlbak.log 2>/var/log/mysqlbak.log
echo "mysql backup begin at `date +%F %T`."

# 本地备份
mysqldump -uroot -p$passwd --default-character-set=utf8 discuz >$backdir/$week.sql
# 同步备份到远程机器
rsync -az $backdir/$week.sql $r_backupIP/$today.sql

echo "mysql backup end at `date +%F %T`."

然后加入cron

0 3 * * * /bin/bash /usr/local/sbin/mysqlbak.sh

13、服务器上跑的是LNMP环境,近期总是有502现象。502为网站访问的状态码,200正常,502错误是nginx最为普通的错误状态码。由于502只是暂时的,并且只要一重启php-fpm服务则502消失,但不重启的话,则会一直持续很长时间。所以有必要写一个监控脚本,监控访问日志的状态码,一旦发生502,则自动重启一下php-fpm

我们设定:

  • access_log /data/log/access.log
  • 脚本死循环,每10s检测一次(假设每10s钟的日志条数为300左右)
  • 重启php-fpm的方法是/etc/init.d/php-fpm restart
#!/bin/bash
access_log="/data/log/access.log"
N=10
while :
do
   # 因为10秒大概产生300条日志记录
   tail -n300 $access_log > /tmp/log
   # 拿出log中包含502的日志行数
   n_502=`grep -c "502" /tmp/log`
   # 如果行数大于10
   if [ $n_502 -ge $N ]
   then
      # 就记录一下系统状态
      top -bn1 > /tmp/`date +%H%M%S`-top.log
      vmstat 1 5 > /tmp/`date +%H%M%S`-vm.log
      # 然后才重启服务,并把错误信息重定向
      /etc/init.d/php-fpm restart 2> /dev/null
      # 重启php-fpm服务后,应先暂缓1分钟,而后继续每隔10s检测一次
      sleep(60)
   fi
   sleep(10)
done

14、需求: 根据web服务器上的访问日志,把一些请求量非常高的ip给拒绝掉!

分析: 我们要做的,不仅是要找到哪些ip请求量不合法,并且还要每隔一段时间把之前封掉的ip(若不再继续请求了)给解封。 所以该脚本的关键点在于定一个合适的时间段和阈值。

比如, 我们可以每一分钟去查看一下日志,把上一分钟的日志给过滤出来分析,并且只要请求的ip数量超过100次那么就直接封掉。 而解封的时间又规定为每半小时分析一次,把几乎没有请求量的ip给解封!

参考日志文件片段:

157.55.39.107 [20/Mar/2015:00:01:24 +0800] www.aminglinux.com “/bbs/thread-5622-3-1.html” 200 “-” “Mozilla/5.0 (compatible; bingbot/2.0; +http://www.bing.com/bingbot.htm)”
61.240.150.37 [20/Mar/2015:00:01:34 +0800] www.aminglinux.com “/bbs/search.php?mod=forum&srchtxt=LNMP&formhash=8f0c7da9&searchsubmit=true&source=hotsearch” 200 “-” “Mozilla/5.0 (compatible; bingbot/2.0; +http://www.bing.com/bingbot.htm)”

脚本实现如下:

#!/bin/bash
## 日志文件路径
log_file="/home/logs/client/access.log"
## 当前时间减一分钟的时间
d1=`date -d "-1 minute" +%H:%M`
## 当前时间的分钟段
d2=`date +%M`
## iptables命令所在的路径
ipt="/sbin/iptables"
## 用于存储访问日志里的ip
ips="/tmp/ips.txt"

## 封ip
block(){
   ## 把日志文件中的ip过滤出来,去掉重复的ip,并统计ip的重复次数以及对ip进行排序,最后将结果写到一个文件中
   grep "$d1:" $log_file |awk '{print $1}' |sort -n |uniq -c |sort -n > $ips
   ## 将文件里重复次数大于100的ip迭代出来
   for ip in `awk '$1 > 100 {print $2}' $ips`
   do
      ## 通过防火墙规则对这些ip进行封禁
      $ipt -I INPUT -p -tcp --dport 80 -s $ip -j REJECT
      ## 将已经封禁的ip输出到一个文件里存储
      echo "`date +%F-%T` $ip" >> /tmp/badip.txt
   done
}

## 解封ip
unblock(){
   ## 将流量小于15的规则索引过滤出来
   for i in `$ipt -nvL --line-number |grep '0.0.0.0/0' |awk '$2 < 15 {print $1}' |sort -nr`
   do
      ## 通过索引来删除规则
      $ipt -D INPUT $i
   done
   ## 清空规则中的数据包计算器和字节计数器
   $ipt -Z
}

## 为整点或30分钟就是过了半个小时,就需要再进行分析
if [ $d2 == "00" ] || [ $d2 == "30" ]
then
   unblock
   block
else
   block
fi

你可能感兴趣的:(分享几个实用脚本)