个人博客地址:
http://www.z-dig.com/shell-scripting-in-19-cases.html
本文所有题目来自于老男孩51cto博客,地址如下:
http://oldboy.blog.51cto.com/2561410/1632876
转载请注明最原始出处。
本文中所有题目答案都是按我自己的思路整理的,并不代表最完美答案,适合新手学习参考。
由于代码是从word中复制过来的,文章发布后发现所有的代码格式都乱了(一律左对齐了),�r(�s��t)�q,之后又用了很长时间手动更改代码的格式,因为是手动,难免有疏忽,而且改的也不是很规范,格式上错乱的地方望见谅。
目录:
1 监控mysql主从同步... 2
2 批量创建文件... 3
3 批量改名... 4
4 批量创建账户... 4
5 判断当前局域网存在的主机... 5
6 写一个脚本解决DOS攻击生产案例... 5
7 开发mysql多实例启动脚本... 6
8 对MySQL数据库进行分库备份... 8
9 对MySQL数据库进行分库加分表备份... 8
10 字符串打印... 9
11 计算比较... 9
12 打印菜单(堡垒机)... 11
13 检测web服务及mysql服务... 12
14 监控memcached. 15
15 监控web站点目录是否被篡改... 16
16 rsync服务启动脚本... 17
17 抓阄题... 18
18 暴力破解密码... 20
19 批量检查多个网站地址是否正常... 21
(生产实战案例):监控MySQL主从同步是否异常,如果异常,则发送短信或者邮件给管理员。提示:如果没主从同步环境,可以用下面文本放到文件里读取来模拟:
阶段1:开发一个守护进程脚本每30秒实现检测一次。
阶段2:如果同步出现如下错误号(1158,1159,1008,1007,1062),则跳过错误。
阶段3:请使用数组技术实现上述脚本(获取主从判断及错误号部分)
#!/bin/bash #lixinyu linux #2015-5-15 #监控mysql主从同步 USER=root PASSWORD=123456 PORT=3307 error=(1158 1159 1008 1007 1062) MYSQLCMD="mysql -u$USER -p$PASSWORD -S /data/$PORT/mysql.sock" is_run(){ [ `lsof -i:$PORT|wc -l` -lt 2 ]&&{ echo "mysql server is stoping" exit 1 } } status_array(){ status=($($MYSQLCMD -e "show slave status\G"|egrep "_Running|Last_Errno|Behind_Master"|awk '{print $NF}')) } status_error(){ flag=0 for((i=0;i<${#error[*]};i++)) do if [ "$1" == "${error[$i]}" ] then $MYSQLCMD -e "stop slave;set global sql_slave_skip_counter=1;start slave;" else let flag=flag+1 fi done [ $flag -ne 0 ]&&echo "MySQL slave is failed, errorno is $1" } judge_slave(){ status_array if [ "${status[0]}" == "Yes" -a "${status[1]}" == "Yes" -a "${status[3]}" = "0" ] then echo "MySQL slave is ok" else status_error ${status[2]} fi } main(){ while true do is_run judge_slave sleep 5 done } main
使用for循环在/oldboy目录下通过随机小写10个字母加固定字符串oldboy批量创建10个html文件,名称例如为:
jdxexendbe_oldboy.html ugaywanjlm_oldboy.html xzzruhdzda_oldboy.html
qcawgsrtkp_oldboy.html vfrphtqjpc_oldboy.html
解答脚本
#!/bin/bash if [ ! -d /oldboy ] then mkdir /oldboy -p fi for ((i=1;i<=10;i++)) do touch /oldboy/`echo $RANDOM|md5sum|cut -c 1-10`_oldboy.html done
将以上文件名中的oldboy全部改成oldgirl(用for循环实现),并且html改成大写。请用两种以上方法实现
方法一
#!/bin/bash cd /oldboy name=($(ls /oldboy)) for ((i=0;i<${#name[*]};i++)) do /bin/mv ${name[i]} `ls ${name[i]}|sed -rn 's#(^.*)_oldboy.html#\1_oldgirl.HTML#gp'` done
改回来(也可以作为一种方法)
rename "oldgirl.HTML" "oldboy.html" *.HTML
方法二
#!/bin/bash cd /oldboy for f in `ls /oldboy` do /bin/mv $f `echo $f|sed -rn 's#(^.*)oldboy.html#\1oldgirl.HTML#gp' ` done
批量创建10个系统帐号oldboy01-oldboy10并设置密码(密码为随机8位字符串)。
#!/bin/bash random(){ password=`echo $RANDOM|md5sum|cut -c 1-8` } for user in `seq -w 10` do useradd oldboy$user random echo $password|passwd --stdin oldboy$user echo oldboy$user $password >>/opt/user.txt done
写一个脚本,实现判断10.0.0.0/24网络里,当前在线用户的IP有哪些(方法有很多)
#!/bin/bash . /etc/init.d/functions for ((i=1;i<=254;i++)) do ping -c1 10.0.0.$i >/dev/null 2>&1 if [ $? -eq 0 ] then action "10.0.0.$i is ok" /bin/true else action "10.0.0.$i is ok" /bin/false fi done
提示:根据web日志或者或者网络连接数,监控当某个IP并发连接数或者短时内PV达到100,即调用防火墙命令封掉对应的IP,监控频率每隔3分钟。防火墙命令为:iptables-A INPUT -s 10.0.1.10 -j DROP。
方法一(注意在函数中,iptables命令要使用全路径)
#!/bin/bash count=(`egrep "EST" netstat.log |awk -F "[ :]+" '{print $6}'|sort -n|uniq -c|awk '{print $1}'`) ip=(`egrep "EST" netstat.log |awk -F "[ :]+" '{print $6}'|sort -n|uniq -c|awk '{print $2}'`) iptables(){ for ((i=0;i<${#count[*]};i++)) do if [ ${count[$i]} -gt 10 ] && [ `/sbin/iptables -L -n|grep "${ip[$i]}"|wc -l` -lt 1 ] then echo `date` >>/opt/DOS.log echo ${count[$i]} ${ip[$i]} >> /opt/DOS.log /sbin/iptables -A INPUT -s ${ip[$i]} -j DROP fi done } main(){ while true do iptables sleep 180 done } main
方法二:
while true do #awk '{print $1}' access.log|grep -v "^$"|sort|uniq -c >/tmp/tmp.log grep EST a.log|awk -F '[ :]+' '{print $6}'|sort|uniq -c >/tmp/tmp.log #netstat -an|grep EST|awk -F '[ :]+' '{print $6}'|sort|uniq -c >/tmp/tmp.log exec </tmp/tmp.log while read line do ip=`echo $line|awk '{print $2}'` count=`echo $line|awk '{print $1}'` if [ $count -gt 3 ] && [ `iptables -L -n|grep "$ip"|wc -l` -lt 1 ] then iptables -I INPUT -s $ip -j DROP echo "$line is dropped" >>/tmp/droplist.log fi done sleep 5 done
加入定时任务
*/3 * * * * /bin/sh /server/scripts/ip_drop.sh >/dev/null 2>&1
已知mysql多实例启动命令为:mysqld_safe--defaults-file=/data/3306/my.cnf &
停止命令为:mysqladmin -u root -poldboy123 -S /data/3306/mysql.sockshutdown
请完成mysql多实例启动启动脚本的编写
要求:用函数,case语句、if语句等实现。
#!/bin/bash #lixinyu linux #2015-5-15 # chkconfig: 2345 25 60 # description: mysql start and stop scripts . /etc/init.d/functions DIR=/data/3306 USER=root PASSWORD=123456 PORT=3306 function mysql_start(){ PID=`lsof -i:$PORT|wc -l` [ $PID -lt 2 ]&&{ /usr/local/sbin/mysqld_safe --defaults-file=$DIR/my.cnf >/dev/null 2>&1 & if [ $? -eq 0 ] then sleep 3 action "mysqld is start" /bin/true else action "mysqld is start" /bin/false fi return 0 }||{ action "The mysql is running now" /bin/false return 1 } } function mysql_stop(){ PID=`lsof -i:$PORT|wc -l` [ $PID -ge 2 ]&&{ /usr/local/sbin/mysqladmin -u $USER -p"$PASSWORD" -S $DIR/mysql.sock shutdown >/dev/null 2>&1 & if [ $? -eq 0 ] then sleep 3 action "mysqld is stop" /bin/true else action "mysqld is stop" /bin/false fi return 0 }||{ action "The mysql is stoping now" /bin/false return 1 } } function USAGE(){ echo "USAGE:$0 {start|stop|restart}" } [ $# -ne 1 ]&&{ USAGE exit 1 } case "$1" in start) mysql_start ;; stop) mysql_stop ;; restart) mysql_stop mysql_start ;; *) USAGE esac
#!/bin/bash #lixinyu linux #2015-5-20 user=root password=123456 sock=/data/3306/mysql.sock MYCMD="mysql -u$user -p$password -S $sock" MYDUMP="mysqldump -u$user -p$password -S $sock" for database in `$MYCMD -e "show databases;"|sed '1d'|egrep -v 'mysql|_schema'` do $MYDUMP -B --master-data=2 --events --single-transaction $database|gzip >/opt/${database}_$(date +%F).sql.gz done
#!/bin/bash #lixinyu linux #2015-5-20 user=root password=123456 sock=/data/3306/mysql.sock MYCMD="mysql -u$user -p$password -S $sock" MYDUMP="mysqldump -u$user -p$password -S $sock" for database in `$MYCMD -e "show databases;"|sed '1d'|egrep -v "mysql|_schema"` do mkdir /backup/${database} -p for table in `$MYCMD -e "show tables from $database"|sed "1d"` do $MYDUMP $database $table|gzip >/backup/${database}/${database}.${table}_$(date +%F).sql.gz done done
请用至少两种方法实现!
bash for循环打印下面这句话中字母数不大于6的单词(昆仑万维面试题)。
I am oldboy teacher welcome to oldboy training class.
方法一
#!/bin/bash for n in I am oldboy teacher welcome to oldboy training class do if [ ${#n} -le 6 ];then echo $n fi done
方法二
#!/bin/bash chars=(I am oldboy teacher welcome to oldboy training class) for ((i=0;i<${#chars[*]};i++)) do if [ ${#chars[i]} -le 6 ];then echo ${chars[i]} fi done
开发shell脚本分别实现以脚本传参以及read读入的方式比较2个整数大小。以屏幕输出的方式提醒用户比较结果。注意:一共是开发2个脚本。当用脚本传参以及read读入的方式需要对变量是否为数字、并且传参个数做判断。
#!/bin/bash read -t 30 -p "pls input two num:" a b [ ${#a} -eq 0 -o ${#b} -eq 0 ]&&{ echo "you need input two num" exit 1 } expr $a + 1 &>/dev/null RETVAL_A=$? expr $b + 1 &>/dev/null RETVAL_B=$? [ $RETVAL_A -ne 0 -o $RETVAL_B -ne 0 ]&&{ echo "one of your input is not int." exit 1 } [ $a -gt $b ]&&{ echo "$a>$b" exit 0 } [ $a -eq $b ]&&{ echo "$a=$b" exit 0 } [ $a -lt $b ]&&{ echo "$a<$b" exit 0 }
第二个
#!/bin/bash #read -t 30 -p "pls input two num:" a b #[ ${#a} -eq 0 -o ${#b} -eq 0 ]&&{ # echo "you need input two num" # exit 1 #} [ $# -ne 2 ]&&{ echo "USAGE:$0 INT1 INT2" exit 1 } a=$1 b=$2 expr $a + 1 &>/dev/null RETVAL_A=$? expr $b + 1 &>/dev/null RETVAL_B=$? [ $RETVAL_A -ne 0 -o $RETVAL_B -ne 0 ]&&{ echo "one of your input is not int." exit 1 } if [ $a -eq $b ] then echo "$a=$b" elif [ $a -gt $b ] then echo "$a>$b" else echo "$a<$b" fi
打印选择菜单,一键安装Web服务:
[root@oldboyscripts]# sh menu.sh
1.[install lamp]
2.[install lnmp]
3.[exit]
pls input the num you want:
要求:
1、当用户输入1时,输出“startinstalling lamp.”然后执行/server/scripts/lamp.sh,脚本内容输出"lampis installed"后退出脚本;
2、当用户输入2时,输出“startinstalling lnmp.”然后执行/server/scripts/lnmp.sh输出"lnmpis installed"后退出脚本;
3、当输入3时,退出当前菜单及脚本;
4、当输入任何其它字符,给出提示“Input error”后退出脚本。
5、要对执行的脚本进行相关条件判断,例如:脚本是否存在,是否可执行等。
本题只是一个简单案例,练习cat的使用
#!/bin/bash menu(){ cat <<END 1.[install lamp] 2.[install lnmp] 3.[exit] pls input the num you want: END } menu read -t 15 a [ $a -eq 1 ]&&{ echo "installing lamp" sleep 3 echo "lamp is installed." exit } [ $a -eq 2 ]&&{ echo "installing lnmp" sleep 3 echo "lnmp is installed." exit } [ $a -eq 3 ]&&{ exit } [ ! $a -eq 1 -o ! $a -eq 2 -o ! $a -eq 3 ] &&{ echo "bye" exit 1 }
1、监控web服务是否正常,不低于3种监控策略。
2、监控db服务是否正常,不低于3种监控策略。
要求间隔1分钟,持续监控。
本题只是给出解决问题的思路,写的比较简单和仓促,不代表生产环境脚本
检测web
[root@c66-kslx 0502]# cat web_curl.sh #!/bin/sh while true do NGINX_NU=`curl -I -s -w "%{http_code}" -o /dev/null 192.168.235.129` if [ "${NGINX_NU}" == "200" ] then echo "nginx server is OK" else echo "nginx server is not ok" fi sleep 1 done [root@c66-kslx 0502]# cat web_lsof.sh #!/bin/sh while true do NGINX_NU=`lsof -i:80|grep nginx|wc -l` if [ ${NGINX_NU} -ge 2 ] then echo "nginx server is OK" else echo "nginx server is not ok" fi sleep 1 done [root@c66-kslx 0502]# cat web_nmap.sh #!/bin/sh while true do NGINX_NU=`nmap 192.168.235.129 -p 80|grep open|wc -l` if [ ${NGINX_NU} -eq 1 ] then echo "nginx server is OK" else echo "nginx server is not ok" fi sleep 1 done [root@c66-kslx 0502]# cat web_ps.sh #!/bin/sh while true do NGINX_NU=`ps aux |grep nginx|wc -l` if [ ${NGINX_NU} -ge 2 ] then echo "nginx server is OK" else echo "nginx server is not ok" fi sleep 1 done [root@c66-kslx 0502]# cat web_wget.sh #!/bin/sh while true do wget --spider --timeout=10 --tries=2 192.168.235.129 >/dev/null 2>&1 if [ $? -eq 0 ] then echo "nginx server is OK" else echo "nginx server is not ok" fi sleep 1 done
检测mysql
[root@c66-kslx 0502]# cat mysql_lsof.sh #!/bin/sh while true do MYSQL_NU=`lsof -i:3306|wc -l` if [ ${MYSQL_NU} -ge 2 ] then echo "mysql server is OK" else echo "mysql server is not ok" fi sleep 1 done [root@c66-kslx 0502]# cat mysql_netstat.sh #!/bin/sh while true do MYSQL_NU=`netstat -lutup |grep mysql |wc -l` if [ ${MYSQL_NU} -ge 1 ] then echo "mysql server is OK" else echo "mysql server is not ok" fi sleep 1 done [root@c66-kslx 0502]# cat mysql_ps.sh #!/bin/sh while true do MYSQL_NU=`ps aux | grep mysql|wc -l` if [ ${MYSQL_NU} -ge 2 ] then echo "mysql server is OK" else echo "mysql server is not ok" fi sleep 1 done [root@c66-kslx 0502]# cat mysql_show.sh #!/bin/sh while true do mysql -uroot -p"123456" -S /data/3306/mysql.sock -e "show databases;" >/dev/null 2>&1 if [ $? -eq 0 ] then echo "mysql server is OK" else echo "mysql server is not ok" fi sleep 1 done
监控memcache服务是否正常,模拟用户(web客户端)检测。
使用nc命令加上set/get来模拟检测,以及监控响应时间及命中率。
脚本写的比较屎,像一坨,也是,给出方法
#!/bin/sh while true do mem=`lsof -i:11211|wc -l` if [ $mem -gt 1 ] then printf "set key_test 0 0 4\r\ntest\r\n"|nc 127.0.0.1 11211 >/dev/null 2>&1 value1=`echo $?` printf "get key_test\r\n"|nc 127.0.0.1 11211 >/dev/null 2>&1 value2=`echo $?` printf "delete key_test\r\n"|nc 127.0.0.1 11211 >/dev/null 2>&1 value3=`echo $?` if [ $value1 -eq 0 -a $value2 -eq 0 -a $value3 -eq 0 ] then # echo "$(date +'%F %H:%M') memcached server is ok" >>/opt/memcached.log else echo "$(date +'%F %H:%M') memcached server is error">> /opt/memcached_error1.log mail -s "memcached is error" [email protected] </opt/memcached_error1.log exit 1 fi else echo "$(date +'%F %H:%M') memcached server not start" >>/opt/memcached_error2.log memcached -d -c 10240 -p 11211 -m 16 -P /var/run/memcached.pid -u root [ $? -eq 0 ]&&{ echo "$(date +'%F %H:%M') memcached server start now" >> /opt/memcached_error2.log }||{ echo "$(date +'%F %H:%M') memcached server start filed, pls dispose" >> /opt/memcached_error2.log mail -s "memcached start filed" [email protected] </opt/memcached_error2.log exit 1 } fi sleep 5 done
监控web站点目录(/var/html/www)下所有文件是否被恶意篡改(文件内容被改了),如果有就打印改动的文件名(发邮件),定时任务每3分钟执行一次(10分钟时间完成)。
方法一,使用inotify方法,这里不再写脚本,很简单
wget http://github.com/downloads/rvoicilas/inotify-tools/inotify-tools-3.14.tar.gz tar zxf inotify-tools-3.14.tar.gz cd inotify-tools-3.14 ./configure --prefix=/usr/local/inotify-tools-3.14 make && make install ln -s /usr/local/inotify-tools-3.14 /usr/local/inotify-tools /usr/local/inotify-tools-3.14/bin/inotifywait -mrq --timefmt '%d/%m/%y %H:%M' --format '%T %w%f' -e create,delete /backup
方法二,使用md5校对(感谢张耀同学的思路!)
#!/bin/bash DIR=/var/html/www DBDIR=/server md5db=$DBDIR/md5.db newdb=$DBDIR/new.db diffdb=$DBDIR/diff.db checklog=/tmp/check.log [ ! -d "$DIR" ]&&{ echo "This is not web" exit 1 } [ ! -d "$DBDIR" ] && mkdir $DBDIR -p for i in $dm5db $newdb $diffdb $checklog do [ ! -d "$i" ] && touch $i done while true do md5sum -c $md5db|grep FAILED >>$checklog 2>&1 find $DIR -type f >$newdb diff $newdb $diffdb >>$checklog 2>&1 [ -s "$checklog" ] && \ # mail -s "web check $(date +%F)" [email protected] <$checklog echo haha sleep 300 done
写网络服务独立进程模式下rsync的系统启动脚本
例如:/etc/init.d/rsyncd{start|stop|restart} 。
要求:
1.要使用系统函数库技巧。
2.要用函数,不能一坨SHI的方式。
3.可被chkconfig管理。
#!/bin/bash # chkconfig: 2345 31 61 # description: start rsync and stop rsync scripts. #lixinyu linux #2015-5-15 . /etc/init.d/functions PID_FILE=/var/run/rsyncd.pid rsync_start(){ if [ -f $PID_FILE ] then action "rsync is running" /bin/false else rsync --daemon if [ $? -eq 0 ] then sleep 1 action "rsync is start" /bin/true else action "rsync is start" /bin/false fi fi } rsync_stop(){ if [ -f $PID_FILE ] then kill -USR2 `cat $PID_FILE` if [ $? -eq 0 ] then rm -rf $PID_FILE sleep 1 action "rsync is stop" /bin/true else action "rsync is stop" /bin/false fi else action "rsync is stoping" /bin/false fi } USAGE(){ echo "USAGE:$0 {start|stop|restart}" exit 1 } [ $# -ne 1 ]&&{ USAGE } case $1 in start) rsync_start RETVAL=$? ;; stop) rsync_stop RETVAL=$? ;; restart) rsync_stop rsync_start RETVAL=$? ;; *) USAGE esac
exit $RETVAL
有N个学生,选出其中三个参加实践
要求:
1、执行脚本后,想去的同学输入英文名字全拼,产生随机数01-99之间的数字,数字越大就去参加项目实践,前面已经抓到的数字,下次不能在出现相同数字。
2、第一个输入名字后,屏幕输出信息,并将名字和数字记录到文件里,程序不能退出继续等待别的学生输入。
此题的思路详解如下:
http://www.z-dig.com/the-lottery-of-shell-script-example.html
#!/bin/bash file=name_file.db if [ ! -f $file ] then touch $file else >$file fi function ran_num(){ while true do random=$(($RANDOM%99+1)) if [ -z `egrep $random $file|awk '{print $2}'` ] then break fi done } function lot(){ read -p "pls write you name:" name empty [ ${#name} -eq 0 ]&&{ echo "Please enter one name" continue } [ ${#empty} -ne 0 ]&&{ echo "Please enter one name" continue } [ "$name" = "exit" ]&&{ echo "bey dear" exit 0 } ran_num if [ -z `egrep $name $file|awk '{print $1}'` ] then echo "This time obtain random number is:" echo "$name $random" echo "$name $random" >>$file else echo "This time obtain random number is:" egrep $name $file fi } function output(){ lot echo "The random number of the top three:" sort -rn -k2 $file|head -3 [ `cat $file|wc -l` -eq 99 ]&&{ echo "random number not have,bye dear" exit 0 } } function main(){ while true do output done } main
已知下面的字符串是通过RANDOM随机数变量md5sum|cut-c 1-8截取后的结果,请破解这些字符串对应的md5sum前的RANDOM对应数字?
21029299
00205d1c
a3da1677
1f6d12dd
首先要知道RANDOM变量获取的随机数为0-32767之间
#!/bin/bash md5=( 21029299 00205d1c a3da1677 1f6d12dd ) for ((n=0;n<32768;n++)) do for ((i=0;i<${#md5[*]};i++)) do if [ "`echo $n|md5sum|cut -c 1-8`" == "${md5[i]}" ] then echo ${md5[i]} $n fi done done
00205d1c 1346
1f6d12dd 7041
a3da1677 25345
21029299 25667
要求:shell数组方法实现,检测策略尽量模拟用户访问思路
http://www.etiantian.org
http://www.taobao.com
http://oldboy.blog.51cto.com
http://10.0.0.7
#!/bin/bash . /etc/init.d/functions url=( http://www.etiantian.org http://www.taobao.com http://oldboy.blog.51cto.com http://192.168.235.129 http://192.168.235.11 http://192.168.235.12 ) while_url(){ i=0 while [ $i -lt ${#url[*]} ] do wget --spider --timeout=10 --tries=2 ${url[$i]} &>/dev/null if [ $? -eq 0 ] then action "${url[$i]}" /bin/true else action "${url[$i]}" /bin/false fi ((i++)) done } while true do while_url sleep 1 done