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)在服务器本地监控服务端口的常见命令有netstat
、ss
、lsof
2)从远端监控服务器本地端口的命令有telnet
、nmap
、nc
监控服务进程或进程数
此方法适合本地服务器,注意,过滤的是进程的名字。命令为:
ps -ef | grep nginx | wc -l
ps -ef | grep mysql | wc -l
在客户端模拟用户访问
使用wget
或curl
命令进行测试(如果检测数据库,则需要转为通过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)通过命令行检测数据库服务是否正常,只有先确定命令行是正确的,才能确保将它放到脚本里也是正确的。
首先采用端口监控的方式。在服务器本地监控端口的命令有netstat
、ss
、lsof
,具体实现多种命令的方法如下:
[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
- 从远端监控服务器监控本地端口的命令有
telnet
、nmap
、nc
,这三个命令有可能需要事先安装好才能使用,安装方法为:
[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
- 以下是在客户端模拟用户访问的方式进行监控
使用wget
或curl
命令访问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
在远端监控服务器本地端口的命令有telnet
、nmap
、nc
,如下:
[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
以下是在客户端模拟用户访问的监控方式。先通过wget
或curl
命令进行测试。执行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