余苏明的幻想乡

第八 面试题实战 一

第八 面试题实战 一

@(shell脚本)[学习]

[toc]

前言

本章内容来自《跟老男孩学Linux运维:Shell编程实战》第19章内容。
可以说本篇内容相当于整本书的一个总结实战

面试题1:批量生成随机字符文件名

使用for循环在/oldboy目录下批量创建10个html文件,其中每个文件需要包含10个随机小写字母加固定字符串oldboy。例如:txynzwofgg_oldboy.html

分析

随机生成小写字母,可以使用openssl函数生成

1
2
3
4
5
6
7
8
9
10
11
12
#!/bin/bash
#19.1.1随机生成字符
#author:oldboy
#blog:http://oldboy.blog.51cto.com
Path=/oldboy
Num=10
[ -d "$Path" ] || mkdir -p $Path
for n in `seq $Num`
do
random=$(openssl rand -base64 40|sed 's#[^a-z]##g'|cut -c 2-11)
touch $Path/${random}_oldboy.html
done

面试题2:批量改名

将19.1.1所得文件中的oldboy改成oldgirl并且将扩展名html全部大写

问题分析

可以使用sed加也可以使用for循环。

1
2
3
4
for i in `ls`
do
mv -f $i `echo $i|sed 's/oldboy\.html/oldgirl.\Uhtml/g'`
done

也可以使用专门的改名命令,rename

1
rename oldboy.html oldgirl.HTML *.html

面试题3:批量创建特殊要求用户

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

问题分析

主要使用useradd命令和passwd --stdin命令一个创建用户,一个传入密码,随机密码可以用openssl来创建

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
#!/bin/bash
#author:oldboy
#blog:http://oldboy.blog.51cto.com
User="oldboy"
Passfile="/tmp/user.log"
for Num in `seq -w 10`
do
useradd $User$Num #<==创建用户
Pass=$(openssl rand -base64 40|sed 's#[^a-z0-9]##g'|cut -c 2-11)
echo "$Pass"|passwd --stdin $User$Num #<==设置密码
echo -e "user:$User$Num\tpasswd:$Pass" >> $Passfile
done
echo "----------this is oldboy trainning class contents---------"
echo "Passfile:$Passfile"
cat $Passfile

面试题4:扫描网络内存活主机

判断某个网段内当前在线的ip有哪些?

问题分析

有个实用的命令nmap一般预装,没有的话yum install nmap -y
没有yum的话,nmap官网

1
2
3
4
5
#!/bin/bash
Cmd="nmap -sP " #<==快速ping测
Ip="10.0.0.0/24"
Cmd2="nmap-sS " #<==检测端口
$CMD $Ip|awk '/Nmap scan report for/ {print $NF}'

面试题5:解决DDOS攻击

问题分析

根据Web日志或网络连接数,监控当某个ip并发连接数或短时内PV达到100时,即调用防火墙命令封掉对应IP。防火墙命令:iptables -I INPUT -s IP -j DROP

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
#!/bin/bash
# 10_10_3.sh
file=$1
JudgeExt(){ \#<==定义判断扩展名的函数,可以传入日志文件
if expr "$1" : ".*\.log" &>/dev/null
then
: #<==冒号表示什么都不做
else
echo $"usage:$0 xxx.log"
exit 1
fi
}
IpCount(){ \#<==分析日志,对访问的IP去重排序。
grep "ESTABLISHED" $1|awk -F "[ :]+" '{ ++S[$(NF-3)]} END {for(key in S) print S[key],key}'|sort -rn -k1|head -5 >tmp/tmp.log
}
ipt(){
local ip=$1
if [ `iptables -L -n|grep "$ip"|wc -l` -lt 1 ]
then
iptables -I INPUT -s $ip -j DROP
echo "$line is dropped" >> /tmp/droplist_$(date +%F).log
fi
}
main(){
JudgeExt $file
while true
do
IpCount $file
while read line
do
ip=`echo $line|awk '{print $2}'`
count=`echo $line|awk '{print $1}'`
if [ $count -gt 3 ]
then
ipt $ip
fi
done</tmp/tmp.log
sleap 180
done
}
main

面试题6:MySQL数据库分库备份

问题分析

使用for循环

1
2
3
4
5
6
7
8
9
10
11
12
13
#!/bin/bash
PATH="/application/mysql/bin:$PATH" #<==定义mysql命令所在路径
DBPATH=/server/backup
MYUSER=root
MYPASS=oldboy123
SOCKET=/data/3306/mysql.sock
MYCMD="mysql -u$MYUSER -p$MYPASS -S $SOCKET"
MYDUMP="mysqldump -u$MYUSER -p$MYPASS -S $SOCKET"
[ ! -d $DBPATH ] && mkdir -p $DBPATH
for dbname in `$MYCMD -e "show databases;"|sed '1,2d'|egrep -v "mysql|schema"`
do
$MYDUMP $dbname|gzip >$DBPATH/${dbname}_$(date +%F).sql.gz
done

面试题7:MYSQL分库分表备份

问题分析

和上面一样,只是多一个循环嵌套

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
#!/bin/bash
PATH="/application/mysql/bin:$PATH" #<==定义mysql命令所在路径
DBPATH=/server/backup
MYUSER=root
MYPASS=oldboy123
SOCKET=/data/3306/mysql.sock
MYCMD="mysql -u$MYUSER -p$MYPASS -S $SOCKET"
MYDUMP="mysqldump -u$MYUSER -p$MYPASS -S $SOCKET"
[ ! -d $DBPATH ] && mkdir -p $DBPATH
for dbname in `$MYCMD -e "show databases;"|sed '1,2d'|egrep -v "mysql|schema"`
do
mkdir $DBPATH/${dbname}_$(date +%F) -p #<==创建对应目录
for table in `$MYCMD -e "show tables for $dbname;"|sed '1d'`
do
$MYDUMP $dbname $table|gzip >$DBPATH/${dbname}_$(date +%F)/${dbname}_${table}.sql.gz
done
done

面试题8:利用bash for循环打印下面字母数不大于6的单词

问题分析

可以使用${\#char}命令来获取单词长度

面试题9:MySQL主从复制异常监控

问题分析

开发一个守护进程脚本,每30s监控一次MySQL主从复制异常

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
#!/bin/bash
#####################
# this script function is :
# check_mysql_slave_replication_status
# USER YYYY-MM-DD - ACTION
# oldboy 2009-02-10 - Created
#####################
path=/server/scripts #<== 定义脚本存放路径
MAIL_GROUP="1111@qq.com 2222@qq.com"
PAGER_GROUP="18600338340 18911718229"
LOG_FILE="/tmp/web_check.log"
USER=root
PASSWORD=oldboy123
PORT=3307
MYSQLCMD="mysql-u$USER -p$PASSWORD -S /data/$PORT/mysql.sock" #<==登陆数据库命令
error=(1008 1007 1062) #<==可忽略的主从复制错误号
RETVAL=0
[ ! -d "$path" ] && mkdir -p $path
function JudgeError(){ \#<==定义判断主从复制错误的函数
for((i=0;i<${\#error[*]};i++))
do
if [ "$1" == "${error[$i]}" ] #<==如果传入的错误号和数组里的元素相匹配,则执行then后面的命令
then
echo "MYSQL slave errorno is $1,auto repairing it."
$MYSQLCMD -e "stop slave;set global sql_slave_skip_counter=1;start slave;" #<==自动修复
fi
done
return $1
}
function CheckDb(){ \#<==定义检查数据库主从复制状态的函数
status=($(awk -F ':' '/_Running|Last_Errno|_Behind/{print $NF}' slave.log))
expr ${status[3]} + 1 &>/dev/null #<==这个是延迟状态,用于进行是否为数字的判断
if [ $? -ne 0 ];then
status[3]=300 #<==赋值300,当数据库出现复制故障时,延迟这个状态值有可能是NULL,即非数字
fi
if [ "${status[0]}" == "Yes" -a "${status[1]}" == "Yes" -a ${status[3]} -lt 120 ] #<==两个线程都为Yes,并且延迟小于120s,即认为复制状态是正常的。
then
#echo "Mysql slave status is ok"
return 0
else
#echo "mysql replcation is failed"
JudgeError ${status[2]} #<==否则,将错误号${status[2]}传入JudgeError函数
fi
}
function MAIL(){ #<==定义邮件函数
local SUBJECT_CONTENT=$1 #<==将函数的第一个传参赋值给主题变量。
for MAIL_USER in `echo $MAIL_GROUP`
do
mail -s "$SUBJECT_CONTENT " $MAIL_USER <$LOG_FILE
done
}
function PAGER(){ #<==定义手机函数
for PAGER_USER in `echo $PAGER_GROUP`
do
TITLE=$1
CONTACT=$PAGER_USER
HTTPGW=http:/../ #<==发送短信地址
##发送短信报警的命令
#send_message method1
curl -d cdkey=XXXX -d password=xxxx -d phone=$CONTACT -d message="$TITLE[$2]" $HTTPGW
done
}
function SendMsg(){
if [ $1 -ne 0 ]
then
RETVAL=1
NOW_TIME=`date +"%Y-%m-%d %H:%M:%S"`
SUBJECT_CONTENT="mysql slave is error,errorno is $2,${NOW_TIME}."
echo -e "$SUBJECT_CONTENT"|tee $LOG_FILE
MAIL $SUBJECT_CONTENT
PAGER $SUBJECT_CONTENT $NOW_TIME
else
echo "Mysql slave status is ok"
RETVAL=0
fi
return $RETVAL
}
function main(){
while true
do
CheckDb
SendMsg $?
sleep 30
done
}
main

面试题10:比较整数大小

问题分析

先判断是否传参,再判断参数个数,再判断参数类型,最后比较

面试题11:菜单自动化软件部署

问题分析

同上