├── cover ├── picture ├── cover.jpg └── cover2.jpg ├── chaper01 ├── exit.sh ├── sleep.sh ├── heredocument.sh ├── user_add.sh ├── heredoc_tab.sh ├── first.sh ├── automail.sh ├── sys_info.sh ├── printf_menu.sh ├── autofdisk.sh ├── sys_var.sh ├── echo_menu.sh └── calc.sh ├── chaper03 ├── user.txt ├── test.txt ├── for-demo2.sh ├── while_colons.sh ├── while_true.sh ├── exit-demo4.sh ├── for-demo1.sh ├── for-demo3.sh ├── for-demo4.sh ├── until-demo.sh ├── continue-demo1.sh ├── c-style1.sh ├── matrix-star.sh ├── while-demo1.sh ├── exit-demo2.sh ├── break-demo.sh ├── exit-demo1.sh ├── exit-demo3.sh ├── for-demo6.sh ├── for-demo5.sh ├── c-style2.sh ├── multi_table.sh ├── while-demo2.sh ├── sum.sh ├── shape1.sh ├── shape2.sh ├── while_read1.sh ├── user.sh ├── while-demo3.sh ├── while_read2.sh ├── star.sh ├── ping_check1.sh ├── leap_year.sh ├── chess.sh ├── select-demo.sh ├── shape3.sh ├── monkey.sh ├── while-demo4.sh ├── continue-demo2.sh ├── guess_num.sh ├── ping_check2.sh ├── double-color.sh ├── check_http_curl.sh └── IFS-demo.sh ├── chaper05 ├── trap.sh ├── nounset.sh ├── filebak.sh ├── test.sh ├── errexit.sh ├── demo_error2.sh ├── loop.sh ├── demo_error1.sh ├── rename_v1.sh ├── rename_v2.sh ├── randfile.sh ├── progress_bar1.sh ├── parameter.sh ├── progress_bar2.sh ├── diff.sh ├── nginx_logbak.sh ├── empty.sh ├── useradd.sh ├── progress_bar4.sh ├── progress_bar5.sh ├── progress_bar3.sh ├── clobber.sh ├── randpass.sh ├── countdown.sh ├── clock.sh └── mouse.sh ├── chaper06 ├── name.txt ├── tmooc.sh ├── config_sshd.sh ├── roll.sh ├── kernel.sh ├── guestfish.sh ├── movie.sh ├── dhcp.sh ├── clone-vm.sh └── vsftpd.sh ├── chaper04 ├── exec.sh ├── source.sh ├── env.sh ├── fork.sh ├── subshell_03.sh ├── subshell_06.sh ├── subshell_05.sh ├── subshell_03_bug.sh ├── fibo_v1.sh ├── subshell_04.sh ├── function-demo4.sh ├── function-demo3.sh ├── multi_ping_v1.sh ├── fibo_v2.sh ├── multi_ping_v2.sh ├── function-demo2.sh ├── usage.sh ├── check_service.sh ├── function-demo5.sh ├── function-demo1.sh ├── count_sort_v1.sh ├── insertion_sort_v1.sh ├── bubble_sort.sh ├── insertion_sort_v2.sh ├── multi_procs.sh ├── count_sort_v2.sh ├── subshell_02.sh ├── subshell_01.sh ├── multi_ping_v3.sh ├── proc_buble_sort.sh ├── quick_sort.sh ├── nginx_log.sh ├── puzzle.sh └── lnmp.sh ├── chaper02 ├── if_demo3.sh ├── case-demo4.sh ├── if_demo2.sh ├── case-demo6.sh ├── vncserver.sh ├── guess_num.sh ├── ping_test.sh ├── case-demo3.sh ├── check_service.sh ├── case-demo1.sh ├── case-demo5.sh ├── check_http_nmap.sh ├── case-demo2.sh ├── check_http_hash.sh ├── check_http_curl.sh ├── disk_manager.sh ├── if_demo1.sh ├── score.sh ├── menu.sh ├── nginx ├── install_nginx.sh ├── game.sh └── sys_info.sh ├── chaper07 ├── location.sh ├── movie.sh ├── nginx_log.sh ├── monitor.sh ├── mysql_monitor.sh ├── netstat.sh └── blockip.sh ├── README.md └── LICENSE /cover/picture: -------------------------------------------------------------------------------- 1 | picture 2 | -------------------------------------------------------------------------------- /chaper01/exit.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | exit 3 | -------------------------------------------------------------------------------- /chaper01/sleep.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | sleep 1000 3 | -------------------------------------------------------------------------------- /chaper03/user.txt: -------------------------------------------------------------------------------- 1 | jacob 2 | tintin 3 | rose 4 | rick 5 | vicky 6 | -------------------------------------------------------------------------------- /chaper05/trap.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | trap 'echo xx;exit' INT 3 | sleep 100 4 | -------------------------------------------------------------------------------- /chaper03/test.txt: -------------------------------------------------------------------------------- 1 | hello the world 2 | welcome to beijing 3 | Hi Rick 4 | Let's go to play 5 | -------------------------------------------------------------------------------- /cover/cover.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jacobproject/Shell_Scripts/HEAD/cover/cover.jpg -------------------------------------------------------------------------------- /cover/cover2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jacobproject/Shell_Scripts/HEAD/cover/cover2.jpg -------------------------------------------------------------------------------- /chaper06/name.txt: -------------------------------------------------------------------------------- 1 | 李白 2 | 杜甫 3 | 白居易 4 | 孟浩然 5 | 苏轼 6 | 李清照 7 | 欧阳修 8 | 李商隐 9 | 韩愈 10 | 柳宗元 11 | -------------------------------------------------------------------------------- /chaper04/exec.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | #功能描述(Description):使用exec调用其他外部命令或脚本示例. 3 | 4 | exec ls 5 | echo "test" 6 | cd /etc 7 | -------------------------------------------------------------------------------- /chaper04/source.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | #Description:使用source加载外部脚本. 3 | 4 | source /root/tmp.sh 5 | echo "hi,$env" 6 | ls / 7 | -------------------------------------------------------------------------------- /chaper03/for-demo2.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | #描述(Description):基本for语法格式演示. 3 | 4 | for i in 1 2 3 4 5 5 | do 6 | echo $i 7 | done 8 | -------------------------------------------------------------------------------- /chaper03/while_colons.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | #功能描述(Description):死循环语法演示. 3 | 4 | while : 5 | do 6 | echo "hello world" 7 | done 8 | -------------------------------------------------------------------------------- /chaper03/while_true.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | #功能描述(Description):死循环语法演示. 3 | 4 | while true 5 | do 6 | echo "hello world" 7 | done 8 | -------------------------------------------------------------------------------- /chaper03/exit-demo4.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | #功能描述(Description):exit基本语法演示. 3 | #虽然脚本执行没有错误,但是脚本退出状态码为127. 4 | 5 | ls /etc/passwd 6 | exit 127 7 | -------------------------------------------------------------------------------- /chaper03/for-demo1.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | #描述(Description):基本for语法格式演示. 3 | 4 | for i in 1 2 3 4 5 5 | do 6 | echo "hello world" 7 | done 8 | -------------------------------------------------------------------------------- /chaper01/heredocument.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | cat > /tmp/test.txt << HERE 4 | 该文件为测试文件。 5 | 测试完后,记得将该文件删除。 6 | Welcome to Earth. 7 | HERE 8 | 9 | -------------------------------------------------------------------------------- /chaper03/for-demo3.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | #描述(Description):基本for语法格式演示. 3 | #注意:这个示例中i后面没有取值范围,则默认取值为$@. 4 | 5 | for i 6 | do 7 | echo $i 8 | done 9 | -------------------------------------------------------------------------------- /chaper03/for-demo4.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | #描述(Description):基本for语法格式演示. 3 | #注意:这个示例中i后面没有取值范围,则默认取值为$@. 4 | 5 | for i 6 | do 7 | echo $i 8 | done 9 | -------------------------------------------------------------------------------- /chaper04/env.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | #定义几个被其他脚本调用的公共变量. 3 | 4 | file="/etc/passwd" 5 | password="I-have-a-dream" 6 | error_info="Please try again later." 7 | -------------------------------------------------------------------------------- /chaper05/nounset.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | #功能描述(Description):通过设置nounset属性,防止变量未定义导致的意外错误. 3 | 4 | set -u 5 | useradd $1 6 | echo "$2" | passwd --stdin $1 7 | -------------------------------------------------------------------------------- /chaper03/until-demo.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | #until语句仅当条件判断为真时才退出循环. 3 | 4 | i=1 5 | until [ $i -ge 5 ] 6 | do 7 | echo $i 8 | let i++ 9 | done 10 | -------------------------------------------------------------------------------- /chaper03/continue-demo1.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | #功能描述(Description):continue基本语法演示. 3 | 4 | for i in {1..5} 5 | do 6 | [ $i -eq 3 ] && continue 7 | echo $i 8 | done 9 | -------------------------------------------------------------------------------- /chaper03/c-style1.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | #功能描述(Description):C语言风格的for循环示例. 3 | #i从1开始,每循环1次对i进行自加1运算,直到i大于5则循环结束. 4 | 5 | for ((i=1;i<=5;i++)) 6 | do 7 | echo $i 8 | done 9 | -------------------------------------------------------------------------------- /chaper03/matrix-star.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | for i in {1..5} 4 | do 5 | for j in {1..5} 6 | do 7 | echo -n "* " 8 | done 9 | echo 10 | done 11 | -------------------------------------------------------------------------------- /chaper03/while-demo1.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | #功能描述(Description):while基本语法演示. 3 | #无心的死循环. 4 | 5 | i=1 6 | while [ $i -le 5 ] 7 | do 8 | echo "hello world" 9 | done 10 | -------------------------------------------------------------------------------- /chaper05/filebak.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | #功能描述(Description):循环对多个文件进行备份操作. 3 | 4 | for i in `ls /etc/*.conf` 5 | do 6 | tar -czf /root/log/$(basename $i).tar.gz $i 7 | done 8 | -------------------------------------------------------------------------------- /chaper05/test.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | sp='/-\|' 4 | printf ' ' 5 | while true; do 6 | printf '\b%.1s' "$sp" 7 | sp=${sp#?}${sp%???} 8 | sleep 0.1 9 | done 10 | -------------------------------------------------------------------------------- /chaper03/exit-demo2.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | #功能描述(Description):exit基本语法演示. 3 | #exit不指定退出状态码时,返回上一个命令的退出状态码. 4 | #exit前面的命令是cd,命令不会出错,脚本退出后的状态码会是0. 5 | 6 | ls /etc/passwd 7 | cd 8 | exit 9 | -------------------------------------------------------------------------------- /chaper03/break-demo.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | #功能描述(Description):break基本语法演示. 3 | 4 | for i in {1..5} 5 | do 6 | [ $i -eq 3 ] && break 7 | echo $i 8 | done 9 | echo "game over." 10 | -------------------------------------------------------------------------------- /chaper03/exit-demo1.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | #功能描述(Description):exit基本语法演示. 3 | 4 | for i in {1..5} 5 | do 6 | [ $i -eq 3 ] && exit 7 | echo $i 8 | done 9 | echo "game over." 10 | -------------------------------------------------------------------------------- /chaper03/exit-demo3.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | #功能描述(Description):exit基本语法演示. 3 | #虽然脚本中cd命令的参数是错误的,屏幕也会返回错误信息. 4 | #但是,exit指定了退出状态码,整个脚本的退出状态码为0. 5 | 6 | ls /etc/passwd 7 | cd -xyz 8 | exit 0 9 | -------------------------------------------------------------------------------- /chaper05/errexit.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | #功能描述(Description):通过set -e设置命令返回非0状态时脚本直接退出. 3 | 4 | set -e 5 | useradd root 6 | echo "123456" | passwd --stdin root 7 | echo "已经将root密码修改为:123456." 8 | -------------------------------------------------------------------------------- /chaper03/for-demo6.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | #功能描述(Description):错误的演示案例. 3 | 4 | for i in {1..2} 5 | do 6 | for i in {1..2} 7 | do 8 | echo "${i}${i}" 9 | done 10 | done 11 | -------------------------------------------------------------------------------- /chaper04/fork.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | #功能描述(Description):fork子进程的示例. 3 | 4 | #调用外部命令时会导致fork子进程. 5 | sleep 5 6 | 7 | #绝对路径或相对路径调用外部脚本时会导致fork子进程. 8 | /root/tmp.sh 9 | cd /root; ./tmp.sh 10 | -------------------------------------------------------------------------------- /chaper05/demo_error2.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | #功能描述(Description):一个错误演示脚本. 3 | 4 | i=1 5 | while [ $i -le 100 ] 6 | do 7 | echo "i=$i ; sum=$sum" 8 | let sum+=i 9 | done 10 | echo $sum 11 | -------------------------------------------------------------------------------- /chaper03/for-demo5.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | #功能描述(Description):显示1和2的所有排列组合. 3 | 4 | for i in {1..2} 5 | do 6 | for j in {1..2} 7 | do 8 | echo "${i}${j}" 9 | done 10 | done 11 | -------------------------------------------------------------------------------- /chaper01/user_add.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | #Read User's name and password from standard input. 3 | read -p "请输入用户名:" user 4 | read -s -p "请输入密码:" pass 5 | useradd "$user" 6 | echo "$pass" | passwd --stdin "$user" 7 | -------------------------------------------------------------------------------- /chaper04/subshell_03.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | #描述(Description):使用管道开启子Shell导致错误的案例演示. 3 | 4 | sum=0 5 | df | grep "^/" | while read name total used free other 6 | do 7 | let sum+=free 8 | done 9 | echo $sum 10 | -------------------------------------------------------------------------------- /chaper03/c-style2.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | #功能描述(Description):C语言风格的for循环示例. 3 | #i初始值为1,j初始值为5 4 | #每循环一次对i进行自加1运算、对j进行自减1运算,当i大于5则循环结束. 5 | 6 | for ((i=1,j=5;i<=5;i++,j--)) 7 | do 8 | echo "$i $j" 9 | done 10 | -------------------------------------------------------------------------------- /chaper04/subshell_06.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | #描述(Description):使用&后台进程开启子Shell. 3 | 4 | count=0 5 | for i in {1..254} 6 | do 7 | ping -c1 -i0.2 -W1 192.168.4.$i >/dev/null && let count++ & 8 | done 9 | echo $count 10 | -------------------------------------------------------------------------------- /chaper01/heredoc_tab.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | #不能屏蔽Tab键,缩进将作为内容的一部分被输出 4 | #注意hello和world前面是tab键 5 | cat << EOF 6 | hello 7 | world 8 | EOF 9 | 10 | #Tab键将被忽略,仅输出数据内容 11 | cat <<- EOF 12 | hello 13 | world 14 | EOF 15 | -------------------------------------------------------------------------------- /chaper03/multi_table.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | #功能描述(Description):打印9*9乘法表. 3 | 4 | for ((i=1;i<=9;i++)) 5 | do 6 | for ((j=1;j<=i;j++)) 7 | do 8 | echo -n "$i*$j=$[i*j] " 9 | done 10 | echo 11 | done 12 | -------------------------------------------------------------------------------- /chaper03/while-demo2.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | #功能描述(Description):while基本语法演示. 3 | #输出5次whllo world,输出变量i的值. 4 | 5 | i=1 6 | while [ $i -le 5 ] 7 | do 8 | echo "hello world" 9 | echo "$i" 10 | let i++ 11 | done 12 | -------------------------------------------------------------------------------- /chaper01/first.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | <=i;j--)) 8 | do 9 | echo -ne "\033[46m \033[0m" 10 | done 11 | echo 12 | done 13 | -------------------------------------------------------------------------------- /chaper04/subshell_05.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | #描述(Description):执行外部命令或加载其他脚本也会开启子Shell. 3 | 4 | pstree 5 | bash ./env.sh 6 | echo "passwd=$password" 7 | echo "Error:$error_info" 8 | 9 | source ./env.sh 10 | echo "passwd=$password" 11 | echo "Error:$error_info" 12 | -------------------------------------------------------------------------------- /chaper02/if_demo3.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | #注意:案例中操作对象用的都是常量,实际编写脚本时很多应该是变量。 3 | 4 | if ! mkdir "/media/cdrom" 5 | then 6 | echo "failed to create cdrom directory." 7 | fi 8 | if ! yum -y -q install ABC 9 | then 10 | echo "failed to install soft." 11 | fi 12 | 13 | -------------------------------------------------------------------------------- /chaper04/subshell_03_bug.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | #描述(Description):使用管道开启子Shell导致错误的案例演示. 3 | 4 | sum=0 5 | df | grep "^/" | while read name total used free other 6 | do 7 | echo "free=$free" 8 | let sum+=free 9 | echo "sum=$sum" 10 | done 11 | echo $sum 12 | -------------------------------------------------------------------------------- /chaper05/demo_error1.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | #功能描述(Description):一个错误演示脚本. 3 | 4 | user1=jacob 5 | user2=tintin 6 | user3=demo 7 | 8 | for i in user1 user2 user3 9 | do 10 | useradd $i 11 | echo "123456" | passwd --stdin $i &>/dev/null 12 | done 13 | echo "创建账户完成." 14 | -------------------------------------------------------------------------------- /chaper01/automail.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | #语法格式: 3 | #命令 << 分隔符 4 | #内容 5 | #分隔符 6 | #系统会自动将两个分隔符之间的内容重定向传递给前面的命令,作为命令的输入。 7 | #注意:分隔符是什么都可以,但前后分隔符必须一致。推荐使用EOF(end of file) 8 | mail -s warning root@localhost << EOF 9 | This is content. 10 | This is a test mail for redirect. 11 | EOF 12 | -------------------------------------------------------------------------------- /chaper02/case-demo4.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | #识别用户输入字符的类型,仅准确识别一位字符. 3 | 4 | read -p "请输入任意字符:" key 5 | case $key in 6 | [a-z]) 7 | echo "您输入的是小写字母.";; 8 | [A-Z]) 9 | echo "您输入的是大写字母.";; 10 | [0-9]) 11 | echo "您输入的是数字.";; 12 | *) 13 | echo "您输入的是其他特殊符号.";; 14 | esac 15 | -------------------------------------------------------------------------------- /chaper03/while_read1.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | #功能描述(Description):循环读取文件中的数据. 3 | #通过IFS定义输入数据的分隔符. 4 | #read定义7个变量,分别对应/etc/passwd每行数据中的7列. 5 | 6 | IFS=":" 7 | while read user pass uid gid info home shell 8 | do 9 | echo -e "My UID:$uid,\tMy home:$home" 10 | done < /etc/passwd 11 | -------------------------------------------------------------------------------- /chaper03/user.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | #功能描述(Description):通过读取用户名列表文件批量创建系统账户 3 | 4 | for i in $(cat user.txt) 5 | do 6 | if id $i &>/dev/null ;then 7 | echo "$i,该账户已经存在!" 8 | else 9 | useradd $i 10 | echo "123456" | passwd --stdin $i 11 | fi 12 | done 13 | -------------------------------------------------------------------------------- /chaper03/while-demo3.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | #功能描述(Description):while基本语法演示. 3 | 4 | i=1 5 | while [ $i -le 5 ] 6 | do 7 | echo "$i" 8 | let i++ 9 | done 10 | echo "-----------------------" 11 | i=1 12 | while [ $i -le 5 ] 13 | do 14 | let i++ 15 | echo "$i" 16 | done 17 | -------------------------------------------------------------------------------- /chaper04/fibo_v1.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | #功能描述(Description):使用数组推导斐波那契数列. 3 | #F(n)=F(n-1)+F(n-2) (n>=3, F(1)=1,F(2)=1). 4 | 5 | fibo=(1 1) 6 | read -p "请输入需要计算的斐波那契数的个数:" num 7 | for ((i=2;i<=$num;i++)) 8 | do 9 | let fibo[$i]=fibo[$i-1]+fibo[$i-2] 10 | done 11 | echo ${fibo[@]} 12 | -------------------------------------------------------------------------------- /chaper04/subshell_04.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | #描述(Description):通过文件重定向读取文件解决Subshell问题. 3 | 4 | tmp_file="/tmp/subshell-$$.txt" 5 | df | grep "^/" > $tmp_file 6 | while read name total used free other 7 | do 8 | let sum+=free 9 | done < $tmp_file 10 | rm -rf $tmp_file 11 | echo $sum 12 | -------------------------------------------------------------------------------- /chaper03/while_read2.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | #功能描述(Description):循环读取文件中的数据. 3 | #通过IFS定义输入数据的分隔符(临时修改,仅对read有效). 4 | #read定义7个变量,分别对应/etc/passwd每行数据中的7列. 5 | 6 | while IFS=":" read user pass uid gid info home shell 7 | do 8 | echo -e "My UID:$uid,\tMy home:$home" 9 | done < /etc/passwd 10 | -------------------------------------------------------------------------------- /chaper02/if_demo2.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | #测试计算机的CPU品牌是AMD还是Intel。 3 | #grep的-q选项,可以让grep进入静默模式,不管过滤到数据还是没有,都不显示输出结果。 4 | #if命令会通过grep命令的返回值自动判断是否过滤到数据。 5 | 6 | if grep -q AMD /proc/cpuinfo; then 7 | echo "AMD CPU" 8 | fi 9 | if grep -q Intel /proc/cpuinfo; then 10 | echo "Intel CPU" 11 | fi 12 | 13 | -------------------------------------------------------------------------------- /chaper05/rename_v1.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | #功能描述(Description):批量修改文件扩展名(对当前目录下的文件重命名). 3 | #Author:http://manual.blog.51cto.com. 4 | 5 | if [[ -z "$1" || -z "$2" ]];then 6 | echo "Usage:$0 旧扩展名 新扩展名." 7 | exit 8 | fi 9 | 10 | for i in `ls *.$1` 11 | do 12 | mv $i ${i%.$1}.$2 13 | done 14 | -------------------------------------------------------------------------------- /chaper07/location.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | #功能描述(Description):给定关键词,脚本输出该关键词在文件中的行与列坐标. 3 | 4 | #正则表达式\<可以匹配单词的开始,\>可以匹配单词的结尾. 5 | #\可以匹配单词the,而不会匹配then或者other等单词. 6 | #key=$1可以读取脚本的第一个位置参数. 7 | 8 | key=$1 9 | 10 | awk '{ for(i=1;i<=NF;i++) {if($i~/'$key'/) print "'$key'的坐标为:"NR"行",i"列"} }' $2 11 | -------------------------------------------------------------------------------- /chaper03/star.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | #version:1 3 | #echo "* * * * *" 4 | 5 | #!/bin/bash 6 | #version:2 7 | #for j in {1..5} 8 | #do 9 | # echo -n "*" 10 | #done 11 | 12 | #!/bin/bash 13 | #version:3 14 | #注意echo命令输出的内容是星星和空格. 15 | for j in {1..5} 16 | do 17 | echo -n "* " 18 | done 19 | echo 20 | -------------------------------------------------------------------------------- /chaper03/ping_check1.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | #功能描述(Description):测试某个网段内所有主机的连通性. 3 | 4 | net="192.168.4" 5 | for i in {1..254} 6 | do 7 | ping -c2 -i0.2 -W1 $net.$i &>/dev/null 8 | if [ $? -eq 0 ];then 9 | echo "$net.$i is up." 10 | else 11 | echo "$net.$i is down." 12 | fi 13 | done 14 | -------------------------------------------------------------------------------- /chaper05/rename_v2.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | #功能描述(Description):批量修改文件扩展名(对指定目录下的文件重命名). 3 | #Author:http://manual.blog.51cto.com. 4 | 5 | if [[ -z "$1" || -z "$2" || -z "$3" ]];then 6 | echo "Usage:$0 指定路径 旧扩展名 新扩展名." 7 | exit 8 | fi 9 | 10 | for i in `ls $1/*.$2` 11 | do 12 | mv $i ${i%.$2}.$3 13 | done 14 | -------------------------------------------------------------------------------- /chaper02/case-demo6.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | #识别用户输入字符的类型(进化版). 3 | 4 | shopt -s extglob 5 | read -p "请输入任意字符:" key 6 | case $key in 7 | +([[:lower:]])) 8 | echo "您输入的是小写字母.";; 9 | +([[:upper:]])) 10 | echo "您输入的是大写字母.";; 11 | +([0-9])) 12 | echo "您输入的是数字.";; 13 | *) 14 | echo "您输入的是其他特殊符号.";; 15 | esac 16 | -------------------------------------------------------------------------------- /chaper02/vncserver.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | #脚本配置的VNC服务器,客户端无需密码即可连接 3 | #客户端仅有查看远程桌面的权限,没有鼠标和键盘的操作权限 4 | rpm --quiet -q tigervnc-server 5 | if [ $? -ne 0 ];then 6 | yum -y install tigervnc-server 7 | fi 8 | x0vncserver AcceptKeyEvents=0 AcceptPointerEvents=0 \ 9 | AlwaysShared=1 SecurityTypes=None rfbport=5908 10 | -------------------------------------------------------------------------------- /chaper03/leap_year.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | #功能描述(Description):判断闰年. 3 | #条件1:能被4整除,但不能被100整除;条件2:能被400整除. 4 | #满足条件1或者条件2之一就是闰年. 5 | 6 | for i in {1..5000} 7 | do 8 | if [[ $[i%4] -eq 0 && $[i%100] -ne 0 || $[i%400] -eq 0 ]];then 9 | echo "$i:是闰年" 10 | else 11 | echo "$i:非闰年" 12 | fi 13 | done 14 | -------------------------------------------------------------------------------- /chaper02/guess_num.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | #功能描述(Description):脚本自动生成10以内的随机数,根据用户的输入,输出判断结果. 3 | 4 | clear 5 | num=$[RANDOM%10+1] 6 | read -p "请输入1-10之间的整数:" guess 7 | 8 | if [ $guess -eq $num ];then 9 | echo "恭喜,猜对了,就是:$num" 10 | elif [ $guess -lt $num ];then 11 | echo "Oops,猜小了." 12 | else 13 | echo "Oops,猜大了." 14 | fi 15 | -------------------------------------------------------------------------------- /chaper01/sys_info.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | #描述信息:本脚本主要目的是获取主机的数据信息(内存、网卡IP、CPU负载) 3 | 4 | localip=$(ifconfig eth0 | grep netmask | tr -s " " | cut -d" " -f3) 5 | mem=$(free |grep Mem |tr -s " " | cut -d" " -f7) 6 | cpu=$(uptime | tr -s " " | cut -d" " -f13) 7 | echo "本机IP地址是:$localip" 8 | echo "本机内存剩余容量为:$mem" 9 | echo "本机CPU 15分钟的平均负载为:$cpu" 10 | -------------------------------------------------------------------------------- /chaper02/ping_test.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | if [ -z "$1" ];then 4 | echo -n "用法: 脚本 " 5 | echo -e "\033[32m域名或IP\033[0m" 6 | exit 7 | fi 8 | 9 | #-c(设置ping的次数),-i(设置ping的间隔描述),-W(设置超时时间) 10 | ping -c2 -i0.1 -W1 "$1" &>/dev/null 11 | if [ $? -eq 0 ];then 12 | echo "$1 is up" 13 | else 14 | echo "$1 is down" 15 | fi 16 | -------------------------------------------------------------------------------- /chaper02/case-demo3.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | #描述:交互脚本,识别用户的输入信息. 3 | #可以输入简写y或全写yes,不区分大小写. 4 | #可以输入简写n或全写no,不区分大小写. 5 | #使用|分隔多个模式匹配,表示或者关系,匹配任意模式即可成功. 6 | 7 | read -p "您确定需要执行该操作吗(y|n)?" key 8 | case $key in 9 | [Yy]|[Yy][Ee][Ss]) 10 | echo "注意:您选择的是yes.";; 11 | [Nn]|[Nn][Oo]) 12 | echo "您选择的是no.";; 13 | *) 14 | echo "无效的输入";; 15 | esac 16 | 17 | -------------------------------------------------------------------------------- /chaper03/chess.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | #功能描述(Description):打印国际象棋棋盘. 3 | 4 | for i in {1..8} 5 | do 6 | for j in {1..8} 7 | do 8 | sum=$[i+j] 9 | if [[ $[sum%2] -ne 0 ]];then 10 | echo -ne "\033[41m \033[0m" 11 | else 12 | echo -ne "\033[47m \033[0m" 13 | fi 14 | done 15 | echo 16 | done 17 | -------------------------------------------------------------------------------- /chaper05/randfile.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | #功能描述(Description):生成随机临时文件. 3 | 4 | #根据进程号生成随机文件. 5 | touch /tmp/$$.tmp 6 | 7 | #根据进程数量生成随机文件. 8 | pnum=`ps aux | wc -l` 9 | touch /tmp/$pnum.tmp 10 | 11 | #根据文件个数生成随机文件. 12 | fnum=`find /etc |wc -l` 13 | touch /tmp/$fnum.tmp 14 | 15 | #根据文件行数生成随机文件. 16 | cnum=`cat /var/log/messages |wc -l` 17 | touch /tmp/$cnum.tmp 18 | -------------------------------------------------------------------------------- /chaper02/check_service.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | if [ -z $1 ];then 3 | echo "错误:未输入服务名称." 4 | echo "用法:脚本名 服务器名称." 5 | exit 6 | fi 7 | if systemctl is-active $1 &>/dev/null ;then 8 | echo "$1已经启动..." 9 | else 10 | echo "$1未启动..." 11 | fi 12 | if systemctl is-enabled $1 &>/dev/null ;then 13 | echo "$1是开机自启动项." 14 | else 15 | echo "$1不是开机自启动项." 16 | fi 17 | -------------------------------------------------------------------------------- /chaper02/case-demo1.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | #使用case进行字母比较 3 | #括号)前面的内容与后面的命令序列之间可以回车换行分隔,也可以没有换行. 4 | 5 | read -p "请输入一个a-f之间的字母:" key 6 | case $key in 7 | a) 8 | echo "I am a.";; 9 | b) 10 | echo "I am b.";; 11 | c) echo "I am c.";; 12 | d) echo "I am d.";; 13 | e) 14 | echo "I am e.";; 15 | f) 16 | echo "I am f.";; 17 | *) 18 | echo "Out of range.";; 19 | esac 20 | -------------------------------------------------------------------------------- /chaper03/select-demo.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | #功能描述(Description):根据用户选择的菜单实现对应的功能. 3 | 4 | echo "请根据提示选择一个选项." 5 | select item in "CPU" "IP" "MEM" "exit" 6 | do 7 | case $item in 8 | "CPU") 9 | uptime;; 10 | "IP") 11 | ip a s;; 12 | "MEM") 13 | free;; 14 | "exit") 15 | exit;; 16 | *) 17 | echo error;; 18 | esac 19 | done 20 | -------------------------------------------------------------------------------- /chaper03/shape3.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | #功能描述(Description):打印各种色块形状. 3 | #练习循环嵌套 4 | 5 | for ((i=1;i<=5;i++)) 6 | do 7 | for ((j=1;j<=i;j++)) 8 | do 9 | echo -ne "\033[46m \033[0m" 10 | done 11 | echo 12 | done 13 | for ((i=4;i>=1;i--)) 14 | do 15 | for ((j=i;j>=1;j--)) 16 | do 17 | echo -ne "\033[46m \033[0m" 18 | done 19 | echo 20 | done 21 | -------------------------------------------------------------------------------- /chaper05/progress_bar1.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | #功能描述(Description):为拷贝文件设计一个进度条效果. 3 | 4 | #防止提前执行Ctrl+C后无法结束进度条. 5 | trap 'kill $!' INT 6 | 7 | #定义函数:实现无限显示不换行的#符号. 8 | bar(){ 9 | while : 10 | do 11 | echo -n '#' 12 | sleep 0.3 13 | done 14 | } 15 | 16 | #调用函数,屏幕显示#进度,直到拷贝结束kill杀死进度函数. 17 | #$!变量保存的是最后一个后台进程的进程号. 18 | bar & 19 | cp -r $1 $2 20 | kill $! 21 | echo "拷贝结束!" 22 | -------------------------------------------------------------------------------- /chaper02/case-demo5.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | #演示扩展通配符的作用. 3 | 4 | shopt -s extglob 5 | read -p "请输入任意字符:" key 6 | case $key in 7 | +([Yy])) 8 | echo "您输入了至少1个[Yy]";; 9 | ?([Nn])o) 10 | echo "您输入的是[Nn]o或仅为o.";; 11 | t*(o)) 12 | echo "您输入的是t或to或too...";; 13 | @([0-9])) 14 | echo "您输入的是单个数字.";; 15 | !([[:punct:]])) 16 | echo "您输入的不是标点符号.";; 17 | *) 18 | echo "您输入的是其他符号.";; 19 | esac 20 | -------------------------------------------------------------------------------- /chaper02/check_http_nmap.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | #功能描述(Description):使用nmap的端口扫描功能监控HTTP端口 3 | ip=192.168.4.254 4 | mail_to=root@localhost 5 | 6 | nmap -n -sS -p80 192.168.4.254 | grep -q "^80/tcp open" 7 | if [ $? -eq 0 ];then 8 | echo "http service is running on $ip" | mail -s http_status_OK $mail_to 9 | else 10 | echo "http service is stoped on $ip" | mail -s http_status_error $mail_to 11 | fi 12 | -------------------------------------------------------------------------------- /chaper04/function-demo4.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | #功能描述(Description):函数中变量的作用域示例. 3 | 4 | #默认定义的变量为当前Shell全局有效. 5 | global_var1="hello" 6 | global_var2="world" 7 | 8 | #定义demo函数,在函数体内定义新的局部变量并修改局部变量. 9 | function demo() { 10 | func_var="Test" 11 | global_var2="Broke Girls" 12 | echo "全局变量:$global_var1 $global_var2" 13 | } 14 | 15 | echo "函数内部变量:[$func_var]" 16 | echo "$global_var1 $global_var2." 17 | -------------------------------------------------------------------------------- /chaper05/parameter.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | #功能描述(Description):演示shift命令的作用,左移位置参数. 3 | 4 | echo "arg1=$1, arg2=$2, arg3=$3, arg4=$4, arg5=$5, arg6=$6, count=$#" 5 | shift 6 | echo "arg1=$1, arg2=$2, arg3=$3, arg4=$4, arg5=$5, arg6=$6, count=$#" 7 | shift 2 8 | echo "arg1=$1, arg2=$2, arg3=$3, arg4=$4, arg5=$5, arg6=$6, count=$#" 9 | shift 1 10 | echo "arg1=$1, arg2=$2, arg3=$3, arg4=$4, arg5=$5, arg6=$6, count=$#" 11 | -------------------------------------------------------------------------------- /chaper05/progress_bar2.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | #功能描述(Description):为拷贝文件设计一个进度条效果. 3 | 4 | #防止提前执行Ctrl+C后无法结束进度条. 5 | trap 'kill $!' INT 6 | 7 | #定义函数:实现无限显示不换行的背景色块. 8 | bar(){ 9 | while : 10 | do 11 | echo -ne '\033[42m \033[0m' 12 | sleep 0.3 13 | done 14 | } 15 | 16 | #调用函数,屏幕显示色块进度,直到拷贝结束kill杀死进度函数. 17 | #$!变量保存的是最后一个后台进程的进程号. 18 | bar & 19 | cp -r $1 $2 20 | kill $! 21 | echo "拷贝结束!" 22 | -------------------------------------------------------------------------------- /chaper03/monkey.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | #功能描述(Description):使用循环计算猴子吃香蕉的问题. 3 | #一只猴子第一天从树上摘了若干根香蕉, 4 | #当即就吃了一半,还不过瘾,又多吃了一根. 5 | #第二天猴子又将剩下的香蕉吃了一半,禁不住诱惑,又多吃了一根香蕉. 6 | #依此类推,每天都将剩余的香蕉吃一半后再多吃一根. 7 | #到了第九天,猴子发现只剩一根香蕉了, 8 | #请问这只猴子在第一天总共摘了多少根香蕉? 9 | 10 | 11 | ##初始化香蕉数量为1,也就是第九天香蕉数位1. 12 | #每循环一次计算前一天的香蕉数量,循环8次得到第一天的香蕉数量. 13 | banana=1 14 | for i in {1..8} 15 | do 16 | banana=$[(banana+1)*2] 17 | done 18 | echo $banana 19 | -------------------------------------------------------------------------------- /chaper04/function-demo3.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | #功能描述(Description):函数中变量的作用域示例. 3 | 4 | #函数体外部的数组和关联数组都是全局变量. 5 | a=(aa bb cc) 6 | declare -A b 7 | b[a]=11 8 | b[b]=22 9 | 10 | #定义demo函数. 11 | #在函数体内定义新的普通数组为全局变量. 12 | #在函数体内定义新的关联数组为局部变量. 13 | 14 | function demo() { 15 | a=(xx yy zz) 16 | declare -A b 17 | b[a]=88 18 | b[b]=99 19 | echo ${a[@]} 20 | echo ${b[@]} 21 | } 22 | 23 | demo 24 | echo ${a[@]} 25 | echo ${b[@]} 26 | -------------------------------------------------------------------------------- /chaper04/multi_ping_v1.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | #Version:1.0 3 | #功能描述(Description):使用函数与&后台进程实现多进程ping测试. 4 | 5 | net="192.168.4" 6 | 7 | multi_ping() { 8 | ping -c2 -i0.2 -W1 $1 &>/dev/null 9 | if [ $? -eq 0 ];then 10 | echo "$1 is up." 11 | else 12 | echo "$1 is down." 13 | fi 14 | } 15 | 16 | #通过循环反复调用函数并将其放入后台并行执行. 17 | for i in {1..254} 18 | do 19 | multi_ping $net.$i & 20 | done 21 | -------------------------------------------------------------------------------- /chaper03/while-demo4.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | #功能描述(Description):while基本语法演示. 3 | #通过grep过滤httpd,检测httpd服务是否为启动状态. 4 | 5 | while ps aux | grep -v grep | grep -q httpd 6 | do 7 | clear 8 | echo " httpd运行状况: " 9 | echo "----------------------------------" 10 | echo -e "\033[32mhttpd 正在运行中...\033[0m" 11 | echo "----------------------------------" 12 | sleep 0.5 13 | done 14 | echo "httpd 被关闭" 15 | -------------------------------------------------------------------------------- /chaper05/diff.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | #功能描述(Description):对比${!字串*}与${!字串@}的区别. 3 | 4 | echo "-----------------------------" 5 | echo -e "\033[32m*将被扩展为一个整体,循环1次结束.\033[0m" 6 | for i in "${!U*}" 7 | do 8 | echo "变量名称为:$i" 9 | done 10 | echo 11 | echo "-----------------------------" 12 | echo -e "\033[32m@将被扩展为独立的单词,循环n次结束.\033[0m" 13 | for i in "${!U@}" 14 | do 15 | echo -e "变量名称为:$i" 16 | done 17 | echo "-----------------------------" 18 | -------------------------------------------------------------------------------- /chaper02/case-demo2.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | #使用case进行字母比较 3 | #模式与后面的命令序列之间的回车可有可无. 4 | 5 | read -p "请输入一个a-c之间的字母:" key 6 | case $key in 7 | a) 8 | echo "I am a.";;& 9 | #使用;;&会继续对后面的模式继续匹配,所以屏幕会继续显示后面的I am aa. 10 | b) 11 | echo "I am b.";; 12 | a) 13 | #使用;&会导致后一个模式匹配中的命令被执行,所以屏幕会继续显示I am c. 14 | echo "I am aa.";& 15 | c) 16 | echo "I am c.";; 17 | a) 18 | echo "I am aaa.";; 19 | *) 20 | echo "Out of range.";; 21 | esac 22 | -------------------------------------------------------------------------------- /chaper04/fibo_v2.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | #功能描述(Description):使用数组推导斐波那契数列. 3 | #F(n)=F(n-1)+F(n-2) (n>=3, F(1)=1,F(2)=1). 4 | 5 | #定义函数. 6 | Fibonacci() { 7 | #前面两个斐波那契数不需要计算,直接设置为1即可. 8 | if [[ $1 -eq 1 || $1 -eq 2 ]];then 9 | echo -n "1 " 10 | else 11 | #后面的斐波那契数永远都是前面两个数的和. 12 | echo -n "$[$(Fibonacci $[$1-1])+$(Fibonacci $[$1-2])] " 13 | fi 14 | } 15 | 16 | for i in {1..10} 17 | do 18 | Fibonacci $i 19 | done 20 | echo 21 | -------------------------------------------------------------------------------- /chaper04/multi_ping_v2.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | #Version:2.0 3 | #功能描述(Description):使用函数与&后台进程实现多进程ping测试. 4 | #使用wait命令等待所有子进程结束后再退出脚本. 5 | 6 | net="192.168.4" 7 | 8 | multi_ping() { 9 | ping -c2 -i0.2 -W1 $1 &>/dev/null 10 | if [ $? -eq 0 ];then 11 | echo "$1 is up." 12 | else 13 | echo "$1 is down." 14 | fi 15 | } 16 | 17 | #通过循环反复调用函数并将其放入后台并行执行. 18 | for i in {1..254} 19 | do 20 | multi_ping $net.$i & 21 | done 22 | wait 23 | -------------------------------------------------------------------------------- /chaper01/printf_menu.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | #Version:1.0 3 | clear 4 | printf "\e[42m%s\n\e[0m" "---------------------------------" 5 | printf "\e[2;10H%s\t\t\n" "这里是菜单" 6 | printf "\e[32m%s\e[0m\n" "1.查看网卡信息" 7 | printf "\e[35m%s\e[0m\n" "2.查看内存信息" 8 | printf "\e[36m%s\e[0m\n" "3.查看磁盘信息" 9 | printf "\e[34m%s\e[0m\n" "4.查看CPU信息" 10 | printf "\e[33m%s\e[0m\n" "5.查看账户信息" 11 | printf "\e[42m%s\n\e[0m" "---------------------------------" 12 | echo 13 | 14 | -------------------------------------------------------------------------------- /chaper05/nginx_logbak.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | #功能描述(Description):使用脚本结合计划任务,定期对Nginx日志进行切割. 3 | 4 | #本脚是按天为单位进行日志分割,如果需要按小时则需要更精确的时间标签. 5 | datetime=$(date +%Y%m%d) 6 | #假设日志目录为源码安装的标准目录,如果不是该目录则需要根据实际情况修改. 7 | logpath=/usr/local/nginx/logs 8 | mv $logpath/access.log $logpath/access-$datetime.log 9 | mv $logpath/error.log $logpath/error-$datetime.log 10 | 11 | #脚本会读取标准日志目录下的nginx.pid文件,该文件中保存有nginx进程的进程号. 12 | #如果该进程文件在其他目录,则需要根据实际情况进行适当修改. 13 | kill -USR1 $(cat $logpath/nginx.pid) 14 | -------------------------------------------------------------------------------- /chaper05/empty.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | #功能描述(Description):读取位置参数,测试是否空文件并删除空文件. 3 | 4 | if [ $# -eq 0 ];then 5 | echo "用法:$0 文件名..." 6 | exit 1 7 | fi 8 | 9 | #测试位置变量个数,个数为0时循环结束. 10 | while (($#)) 11 | do 12 | if [ ! -s $1 ];then 13 | echo -e "\033[31m$1为空文件,正在删除该文.\033[0m" 14 | rm -rf $1 15 | else 16 | [ -f $1 ] && echo -e "\033[32m$1为非空文件.\033[0m" 17 | [ -d $1 ] && echo -e "\033[32m$1为目录,不是文件名.\033[0m" 18 | fi 19 | shift 20 | done 21 | -------------------------------------------------------------------------------- /chaper01/autofdisk.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | #本脚本会自动将vdb整个磁盘分成一个区,将将该分区格式化. 3 | #注意:所有数据均将丢失!!! 4 | #n(新建分区),p(新建主分区),1(主分区编号为1) 5 | #回车(从磁盘哪个位置开始分区,默认从第1个扇区) 6 | #回车(分区到哪个扇区结束,回车代表最后,将整个磁盘分1个区) 7 | #wq(保存退出),mkfs.xfs(格式化命令) 8 | fdisk /dev/vdb << EOF 9 | n 10 | p 11 | 1 12 | 13 | 14 | wq 15 | EOF 16 | 17 | mkfs.xfs /dev/vdb1 18 | 19 | #这里文件或目录的属性测试知识点,可以参考2.4章节的内容 20 | [ ! -d /data ] && mkdir /data 21 | cat >> /etc/fstab << EOF 22 | /dev/vdb1 /data xfs defaults 0 0 23 | EOF 24 | mount -a 25 | -------------------------------------------------------------------------------- /chaper04/function-demo2.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | #功能描述(Description):函数中变量的作用域示例之局部变量. 3 | 4 | #默认定义的变量为当前Shell全局有效. 5 | global_var1="hello" 6 | global_var2="world" 7 | 8 | #定义demo函数,在函数体内定义新的局部变量并修改局部变量. 9 | function demo() { 10 | echo -e "\033[46mfunction [demo] started...\033[0m" 11 | local global_var2="Broke Girls" 12 | echo "调用变量:$global_var1 $global_var2" 13 | echo -e "\033[46mfunction [demo] end.\033[0m" 14 | } 15 | 16 | demo 17 | echo 18 | echo "$global_var1 $global_var2." 19 | -------------------------------------------------------------------------------- /chaper04/usage.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | #功能描述(Description):使用函数输出帮助信息. 3 | 4 | function print_usage() { 5 | cat << EOF 6 | Usage: --help | -h 7 | Print help information for script. 8 | Usage: --memory | -m 9 | Monitor memory information. 10 | Usage: --network | -n 11 | Monitor network interface information. 12 | EOF 13 | } 14 | case $1 in 15 | --memory|-m) 16 | free;; 17 | --network|-n) 18 | ip -s link;; 19 | --help|-h) 20 | print_usage;; 21 | *) 22 | print_usage;; 23 | esac 24 | -------------------------------------------------------------------------------- /chaper04/check_service.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | #功能描述(Description):使用函数检查服务是否启动的案例脚本. 3 | 4 | date_time=$(date +'%Y-%m-%dT%H:%M:%S%z') 5 | 6 | function check_services() { 7 | for i in "$@" 8 | do 9 | if systemctl --quiet is-active ${i}.service; then 10 | echo -e "[$date_time)]: \033[92mservice $i is active\033[0m" 11 | else 12 | echo "[$date_time]: service $i is not active" >&2 13 | fi 14 | done 15 | } 16 | 17 | check_services httpd sshd vsftpd 18 | -------------------------------------------------------------------------------- /chaper04/function-demo5.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | #功能描述(Description):自定义函数返回码. 3 | 4 | #默认以函数中最后一条命令的状态作为返回码. 5 | demo1() { 6 | uname -r 7 | } 8 | 9 | #使用return可以让函数立刻结束,并返回状态码,return的有效范围为0-255. 10 | demo2(){ 11 | echo "start demo2" 12 | return 100 13 | echo "demo2 end." 14 | } 15 | 16 | #如果使用exit定义函数的返回码,则执行函数会导致脚本退出. 17 | demo3() { 18 | echo "hello" 19 | exit 20 | } 21 | 22 | demo1 23 | echo "demo1 status: $?" 24 | demo2 25 | echo "demo2 status: $?" 26 | demo3 27 | echo "demo3 status :$?" 28 | -------------------------------------------------------------------------------- /chaper05/useradd.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | #功能(Description):创建系统账户并配置密码. 3 | 4 | #判断未输入变量值时报错并退出脚本. 5 | read -p "请输入账户名称:" username 6 | username=${username:?"未输入账户名称,请重试."} 7 | 8 | #如果pass变量被赋值,则直接使用该值.如果pass未被赋值,则设置初始密码. 9 | read -p "请输入账户密码,默认密码为[123456]:" pass 10 | pass=${pass:-123456} 11 | 12 | if id $username &> /dev/null ;then 13 | echo "账户:$username已存在." 14 | else 15 | useradd $username 16 | echo "$pass" | passwd --stdin $username &> /dev/null 17 | echo -e "\033[32m[OK]\033[0m" 18 | fi 19 | 20 | -------------------------------------------------------------------------------- /chaper04/function-demo1.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | #功能描述(Description):函数中变量的作用域示例之全局变量. 3 | 4 | #默认定义的变量为当前Shell全局有效. 5 | global_var1="hello" 6 | global_var2="world" 7 | 8 | #定义demo函数,在函数体内定义新的变量以及修改函数外部的变量. 9 | function demo() { 10 | echo -e "\033[46mfunction [demo] started...\033[0m" 11 | func_var="Topic:" 12 | global_var2="Broke Girls" 13 | echo "$func_var $global_var2" 14 | echo -e "\033[46mfunction [demo] end.\033[0m" 15 | } 16 | 17 | demo 18 | echo 19 | echo "$func_var $global_var1 $global_var2." 20 | -------------------------------------------------------------------------------- /chaper03/continue-demo2.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | #功能描述(Description):continue基本语法演示. 3 | 4 | for i in 1 2 5 | do 6 | echo $i 7 | for j in a b 8 | do 9 | echo $j 10 | done 11 | done 12 | echo "---" 13 | for i in 1 2 14 | do 15 | echo $i 16 | for j in a b 17 | do 18 | [ $j == a ] && continue 19 | echo $j 20 | done 21 | done 22 | echo "---" 23 | for i in 1 2 24 | do 25 | echo $i 26 | for j in a b 27 | do 28 | [ $j == a ] && continue 2 29 | echo $j 30 | done 31 | done 32 | -------------------------------------------------------------------------------- /chaper01/sys_var.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | echo "当前账户是:$USER,当前账户的UID是:$UID" 4 | echo "当前账户的家目录是:$HOME" 5 | echo "当前工作目录是:$PWD" 6 | echo "返回0-32767的随机数:$RANDOM" 7 | echo "当前脚本的进程号是$$" 8 | echo "当前脚本的名称为:$0" 9 | echo "当前脚本的第1个参数是:$1" 10 | echo "当前脚本的第2个参数是:$2" 11 | echo "当前脚本的第3个参数是:$3" 12 | echo "当前脚本的所有参数是:$*" 13 | echo "准备创建一个文件..." 14 | touch "$*" 15 | echo "准备创建多个文件..." 16 | touch "$@" 17 | 18 | ls /etc/passwd 19 | echo "我是正确的返回状态码:$?,因为上一条命令执行结果没有问题" 20 | 21 | ls /etc/pas 22 | echo "我是错误的返回状态码:$?,因为上一条命令执行结果有问题,提示无此文件" 23 | 24 | -------------------------------------------------------------------------------- /chaper03/guess_num.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | #功能描述(Description):猜数字小游戏,统计猜的次数. 3 | 4 | num=$[RANDOM%100] 5 | count=0 6 | while : 7 | do 8 | read -p "一个1-100的随机数,你猜是多少:" guess 9 | #使用正则匹配,判断是否输入了字母或符号等无效输入. 10 | [[ $guess =~ [[:alpha:]] || $guess =~ [[:punct:]] ]] && echo "无效输入." && exit 11 | let count++ 12 | if [ $guess -eq $num ];then 13 | echo "恭喜,你猜对了,总共猜了$count次!" 14 | exit 15 | elif [ $guess -gt $num ];then 16 | echo "Oops,猜大了." 17 | else 18 | echo "Oops,猜小了." 19 | fi 20 | done 21 | -------------------------------------------------------------------------------- /chaper04/count_sort_v1.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | #功能描述(Description):计数排序算法,v1版本. 3 | 4 | #创建一个需要排序的数组. 5 | num=(2 8 3 7 1 4 3 2 4 7 4 2 5 1 8 5 2 1 9) 6 | #需要排序的数组中最大值为9,因此创建可以存10个数字的数组,初始值都为0. 7 | count=(0 0 0 0 0 0 0 0 0 0) 8 | 9 | #num数组中有19个数,下标为0-18,使用循环读取num每个元素的值. 10 | #以每个元素的值为count数组的下标,做自加1的统计运算. 11 | for i in `seq 0 18` 12 | do 13 | let count[${num[i]}]++ 14 | done 15 | 16 | #使用循环读取count数组中每个元素值(也就是次数). 17 | #根据次数打印对应下标. 18 | for i in `seq 0 9` 19 | do 20 | for j in `seq ${count[i]}` 21 | do 22 | echo -n "$i " 23 | done 24 | done 25 | echo 26 | -------------------------------------------------------------------------------- /chaper03/ping_check2.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | #功能描述(Description):测试某个网段内所有主机的连通性. 3 | #在对命令进行扩展时,可以使用$()或者是反引号``. 4 | 5 | net="192.168.4" 6 | for i in $(seq 254) 7 | do 8 | ping -c2 -i0.2 -W1 $net.$i &>/dev/null 9 | if [ $? -eq 0 ];then 10 | echo "$net.$i is up." 11 | else 12 | echo "$net.$i is down." 13 | fi 14 | done 15 | 16 | #for i in `seq 254` 17 | #do 18 | # ping -c2 -i0.2 -W1 $net.$i &>/dev/null 19 | # if [ $? -eq 0 ];then 20 | # echo "$net.$i is up." 21 | # else 22 | # echo "$net.$i is down." 23 | # fi 24 | #done 25 | -------------------------------------------------------------------------------- /chaper05/progress_bar4.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | #功能描述(Description):为拷贝文件设计一个进度条效果. 3 | 4 | #防止提前执行Ctrl+C后无法结束进度条. 5 | trap 'kill $!' INT 6 | 7 | #定义变量,存储指针的四个符号. 8 | rotate='|/-\' 9 | 10 | #定义函数:实现动态指针进度条. 11 | bar() { 12 | #回车到下一行打印一个空格,第一次打印指针符号时会把这个空格删除. 13 | #这里的空格主要目的是换行. 14 | printf ' ' 15 | while : 16 | do 17 | #删除前一个字符后,仅打印rotate变量中的第一个字符. 18 | #没循环一次就将rotate中四个字符的位置调整一次. 19 | printf "\b%.1s" "$rotate" 20 | rotate=${rotate#?}${rotate%???} 21 | sleep 0.2 22 | done 23 | } 24 | 25 | bar & 26 | cp -r $1 $2 27 | kill $! 28 | echo "拷贝结束!" 29 | -------------------------------------------------------------------------------- /chaper05/progress_bar5.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | #功能描述(Description):为拷贝文件设计一个进度条效果. 3 | 4 | #防止提前执行Ctrl+C后无法结束进度条. 5 | trap 'kill $!' INT 6 | 7 | #定义变量,存储源与目标的容量大小,目标初始大小为0. 8 | src=$(du -s $1 | cut -f1) 9 | dst=0 10 | 11 | #定义函数:实时对比源文件与目标文件的大小,计算拷贝进度. 12 | bar() { 13 | while : 14 | do 15 | size=$(echo "scale=2;$dst/$src*100" | bc) 16 | echo -en "\r|$size%|" 17 | [ -f $2 ] && dst=$(du -s $2 | cut -f1) 18 | [ -d $2 ] && dst=$(du -s $2/$1 | cut -f1) 19 | sleep 0.3 20 | done 21 | } 22 | 23 | bar $1 $2 & 24 | cp -r $1 $2 25 | kill $! 26 | echo "拷贝结束!" 27 | -------------------------------------------------------------------------------- /chaper02/check_http_hash.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | #功能描述(Description):根据数据的HASH值监控网站数据是否被篡改. 3 | 4 | url="http://192.168.4.5/index.html" 5 | date=$(date +"%Y-%m-%d %H:%M:%S") 6 | 7 | #定义变量并赋值为源数据的HASH值. 8 | source_hash="e3eb0a1df437f3f97a64aca5952c8ea0" 9 | #实时检测网页数据的HASH值 10 | url_hash=$(curl -s $url |md5sum | cut -d ' ' -f1) 11 | 12 | if [ "$url_hash" != "$source_hash" ];then 13 | mail -s http_Warning root@localhost <<- EOF 14 | 检测时间为:$date 15 | 数据完整性校验失败,$url,页面数据被篡改. 16 | 请尽快排查异常. 17 | EOF 18 | else 19 | cat >> /var/log/http_check.log <<- EOF 20 | $date "$url,数据完整性校验正常." 21 | EOF 22 | fi 23 | -------------------------------------------------------------------------------- /chaper05/progress_bar3.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | #功能描述(Description):为拷贝文件设计一个进度条效果. 3 | 4 | #防止提前执行Ctrl+C后无法结束进度条. 5 | trap 'kill $!' INT 6 | 7 | #定义函数:在宽度为50的范围内输出进度条,#和空格占用48个宽度,竖线占用2个宽度. 8 | #1个#组合47个空格=48,2个#组合46个空格=48,3个#组合45个空格=48,依此类推. 9 | #输出完成后不换号将光标切换至行首,准备下一次进度条的显示. 10 | bar(){ 11 | while : 12 | do 13 | pound="" 14 | for ((i=47;i>=1;i--)) 15 | do 16 | pound+=# 17 | printf "|%s%${i}s|\r" "$pound" 18 | sleep 0.2 19 | done 20 | done 21 | } 22 | 23 | #调用函数,显示进度符号,直到拷贝结束kill杀死进度函数. 24 | #$!变量保存的是最后一个后台进程的进程号. 25 | bar & 26 | cp -r $1 $2 27 | kill $! 28 | echo "拷贝结束!" 29 | -------------------------------------------------------------------------------- /chaper01/echo_menu.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | #version:1.0 3 | #这个脚本仅演示菜单输出,没有具体的功能实现 4 | 5 | echo "这是一个打印菜单的例子" 6 | 7 | echo "1.查看网卡信息" 8 | echo "2.查看内存信息" 9 | echo "3.查看磁盘信息 10 | 4.查看CPU信息 11 | 5.查看账户信息" 12 | 13 | #!/bin/bash 14 | #Version:2.0 15 | clear 16 | echo -e "\033[42m---------------------------------\033[0m" 17 | echo -e "\e[2;10H这里是菜单\t\t#" 18 | echo -e "#\e[32m 1.查看网卡信息\e[0m #" 19 | echo -e "#\e[33m 2.查看内存信息\e[0m #" 20 | echo -e "#\e[34m 3.查看磁盘信息\e[0m #" 21 | echo -e "#\e[35m 4.查看CPU信息\e[0m #" 22 | echo -e "#\e[36m 5.查看账户信息\e[0m #" 23 | echo -e "\033[42m---------------------------------\033[0m" 24 | echo 25 | -------------------------------------------------------------------------------- /chaper04/insertion_sort_v1.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | #功能描述(Description):插入排序算法演示,升序排序. 3 | 4 | #通过循环读取5个随机整数赋值给数组变量num. 5 | for x in {1..5} 6 | do 7 | read -p "请输入随机整数:" tmp 8 | num[$x]=$tmp 9 | done 10 | 11 | #默认认为第1个数已经为有序数字. 12 | #直接从第2个数开始跟她前面的数字对比大小. 13 | #使用i控制需要提取出来跟前面比较大小的数字. 14 | for ((i=2;i<=5;i++)) 15 | do 16 | #使用j控制第i个元素前面需要比较的数字. 17 | #j从第i-1个数字元素开始,每循环一次j再往前移动1位. 18 | #如果j小于0了,或者i大于(>)第j个元素的值,则循环退出. 19 | #可以继续循环的条件是j大于等于0,并且第1个元素数字比第j个元素数字小,否则循环就退出. 20 | #如果第i个元素比第j个元素小,则将i个元素和j个元素对调下位置. 21 | tmp=${num[i]} 22 | for ((j=$[i-1];j>=0 && $tmp> /var/log/http_check.log <<- EOF 25 | $date "$url 页面访问正常." 26 | EOF 27 | fi 28 | -------------------------------------------------------------------------------- /chaper05/clobber.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | #功能描述(Description):通过设置锁文件防止脚本重复执行. 3 | 4 | #使用Ctrl+C中断脚本时,删除锁文件. 5 | trap 'rm -rf /tmp/lockfile;exit' HUP INT 6 | 7 | #检查是否存在锁文件,没有锁文件就执行backup备份函数,如果有锁文件脚本则脚本直接退出. 8 | lock_check(){ 9 | if (set -C; :> /tmp/lockfile) 2>/dev/null ;then 10 | backup 11 | else 12 | echo -e "\033[91mWarning:其他用户在执行该脚本.\033[0m" 13 | exit 66 14 | fi 15 | } 16 | 17 | #执行备份前创建所文件,然后执行备份数据库的操作,备份完成后删除锁文件. 18 | #sleep 10实验测试时使用,为了防止小数据库备份太快,无法验证重复执行脚本的效果. 19 | backup(){ 20 | touch /tmp/lockfile 21 | mysqldump --all-database > /var/log/mysql-$(date +%Y%m%d).bak 22 | sleep 10 23 | rm -rf /tmp/lockfile 24 | } 25 | 26 | lock_check 27 | backup 28 | -------------------------------------------------------------------------------- /chaper04/bubble_sort.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | #功能描述(Description):通过简单的数字比较演示冒泡算法. 3 | 4 | #使用数组保存用户输入的6个随机数. 5 | for i in {1..6} 6 | do 7 | read -p "请输入数字:" tmp 8 | if echo $tmp | grep -qP "\D" ;then 9 | echo "您输入的不是数字." 10 | exit 11 | fi 12 | num[$i]=$tmp 13 | done 14 | echo "您输入的数字序列为:${num[@]}" 15 | 16 | #冒泡排序. 17 | #使用i控制进行几轮的比较,使用j控制每轮比较的次数. 18 | #对6个数字而言,需要5论比较,每进行一轮后,下一轮就可以少比较1次. 19 | for ((i=1;i<=5;i++)) 20 | do 21 | for ((j=1;j<=$[6-i];j++)) 22 | do 23 | if [ ${num[j]} -gt ${num[j+1]} ];then 24 | tmp=${num[j]} 25 | num[$j]=${num[j+1]} 26 | num[j+1]=$tmp 27 | fi 28 | done 29 | done 30 | echo "经过排序后数字序列为:${num[@]}" 31 | -------------------------------------------------------------------------------- /chaper04/insertion_sort_v2.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | #功能描述(Description):插入排序算法演示,升序排序. 3 | 4 | #通过循环读取5个随机整数赋值给数组变量num. 5 | for x in {1..5} 6 | do 7 | read -p "请输入随机整数:" tmp 8 | num[$x]=$tmp 9 | done 10 | 11 | #默认认为第1个数已经为有序数字. 12 | #直接从第2个数开始跟她前面的数字对比大小. 13 | #使用i控制需要提取出来跟前面比较大小的数字. 14 | for ((i=1;i<=5;i++)) 15 | do 16 | #使用j控制第i个元素前面需要比较的数字. 17 | #j从第i-1个数字元素开始,每循环一次j再往前移动1位. 18 | #如果j小于0了,或者i大于(>)第j个元素的值,则循环退出. 19 | #可以继续循环的条件是j大于等于0,并且第1个元素数字比第j个元素数字小,否则循环就退出. 20 | #如果第i个元素比第j个元素小,则将i个元素和j个元素对调下位置. 21 | tmp=${num[i]} 22 | j=$[i-1] 23 | while [[ $j -ge 0 && $tmp -lt ${num[j]} ]] 24 | do 25 | num[j+1]=${num[j]} 26 | num[j]=$tmp 27 | let j-- 28 | done 29 | done 30 | echo ${num[@]} 31 | -------------------------------------------------------------------------------- /chaper04/multi_procs.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | #创建命名管道文件,并绑定固定的文件描述符. 4 | pipefile=/tmp/procs_$$.tmp 5 | mkfifo $pipefile 6 | exec 12<>$pipefile 7 | 8 | #通过文件描述符往命名管道中写入5行任意数据,用于控制进程数量. 9 | for i in {1..5} 10 | do 11 | echo "" >&12 & 12 | done 13 | 14 | #通过read命令的-u选项指定从特定的文件描述符中读取数据行. 15 | #每次读取一行,每读取一行就启动一个耗时的进程sleep,并放入后台执行. 16 | #因为命名管道中只要5行数据,读取5行后read会被阻塞,也就无法继续启动sleep进程. 17 | #每当任意一个sleep进程结束,就通过文件描述符再写入任意数据到命名管道. 18 | #当管道中有数据后,read则可以继续读取数据,继续开启新的进程,依次类推. 19 | for j in {1..20} 20 | do 21 | read -u12 22 | { 23 | echo -e "\033[32mstart sleep No.$j\033[0m" 24 | sleep 5 25 | echo -e "\033[31mstop sleep No.$j\033[0m" 26 | echo "" >&12 27 | } & 28 | done 29 | wait 30 | rm -rf $pipefile 31 | -------------------------------------------------------------------------------- /chaper04/count_sort_v2.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | #功能描述(Description):计数排序算法,v2版本. 3 | 4 | #创建一个需要排序的数组. 5 | num=(2 8 3 7 1 4 3 2 4 7 4 2 5 1 8 5 2 1 9) 6 | 7 | #根据num数组的最大值创建一个对应空间大小的统计数组. 8 | #该数组初始值都为0,哪怕没有的数据初始值也为0. 9 | max=${num[0]} 10 | for i in `seq $[${#num[@]}-1]` 11 | do 12 | [ ${num[i]} -gt $max ] && max=${num[i]} 13 | done 14 | for i in `seq 0 $max` 15 | do 16 | count[$i]=0 17 | done 18 | 19 | #循环读取num数组中的每个元素值,以每个元素值为count数组的下标,做自加1的统计工作. 20 | for i in `seq 0 $[${#num[@]}-1]` 21 | do 22 | let count[${num[i]}]++ 23 | done 24 | 25 | #使用循环读取count数组中每个元素值(也就是次数). 26 | #根据次数打印对应下标. 27 | for i in `seq 0 $[${#count[@]}-1]` 28 | do 29 | for j in `seq ${count[i]}` 30 | do 31 | echo -n "$i " 32 | done 33 | done 34 | echo 35 | -------------------------------------------------------------------------------- /chaper02/disk_manager.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | #功能描述(Description):通过读取位置变量,实现分区管理工作. 3 | 4 | #测试位置变量的个数 5 | if [ $# -ne 2 ];then 6 | echo -e "\033[91m\t参数有误...\033[0m" 7 | echo "用法:$0 <磁盘名称> " 8 | exit 9 | fi 10 | 11 | #测试磁盘是否存在 12 | if [ ! -b $1 ];then 13 | echo -e "\033[91m磁盘不存在!\033[0m" 14 | exit 15 | fi 16 | 17 | #根据不同的指令对磁盘进行分区管理 18 | if [[ $2 == create ]];then 19 | parted -s $1 mklabel gpt 20 | elif [[ $2 == new ]];then 21 | parted -s $1 mkpart primary 1 100% 22 | elif [[ $2 == remove ]];then 23 | parted -s $1 rm 1 24 | elif [[ $2 == query ]];then 25 | parted -s $1 print 26 | else 27 | clear 28 | echo -e "\033[91m\t操作指令有误...\033[0m" 29 | echo "可用指令:[create|new|remove|query]." 30 | fi 31 | -------------------------------------------------------------------------------- /chaper03/double-color.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | #功能描述(Descrtiption):机选双色球. 3 | #红色球1-33,蓝色球1-16,红色球号码不可以重复. 4 | #6组双色球,1组蓝色球. 5 | 6 | RED_COL='\033[91m' 7 | BLUE_COL='\033[34m' 8 | NONE_COL='\033[0m' 9 | red_ball="" 10 | 11 | #随机选择1-33的红色球(6个),1-16的篮球(1个). 12 | #每选出一个号码通过+=的方式存储到变量中. 13 | #通过grep判断新选出的红球是否已经出现过,-w选项是过滤单词. 14 | while : 15 | do 16 | clear 17 | echo "---机选双色球---" 18 | tmp=$[RANDOM%33+1] 19 | echo "$red_ball" | grep -q -w $tmp && continue 20 | red_ball+=" $tmp" 21 | echo -en "$RED_COL$red_ball$NONE_COL" 22 | word=$(echo "$red_ball" | wc -w) 23 | if [ $word -eq 6 ]; then 24 | blue_ball=$[RANDOM%16+1] 25 | echo -e "$BLUE_COL $blue_ball$NONE_COL" 26 | break 27 | fi 28 | sleep 0.5 29 | done 30 | 31 | 32 | -------------------------------------------------------------------------------- /chaper05/randpass.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | #功能描述(Description):使用字串截取的方式生成随机密码. 3 | 4 | #定义变量:10个数字+52个字符. 5 | key="abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789" 6 | 7 | randpass(){ 8 | if [ -z "$1" ];then 9 | echo "randpass函数需要一个参数,用来指定提取的随机数个数." 10 | return 127 11 | fi 12 | #调用$1参数,循环提取任意个数据字符. 13 | #用随机数对62取余数,返回的结果为[0-61]. 14 | pass="" 15 | for i in `seq $1` 16 | do 17 | num=$[RANDOM%${#key}] 18 | local tmp=${key:num:1} 19 | pass=${pass}${tmp} 20 | done 21 | echo $pass 22 | } 23 | 24 | #randpass 8 25 | #randpass 16 26 | 27 | #创建临时测试账户,为账户配置随机密码,并将密码保存至/tmp/pass.log. 28 | useradd tomcat 29 | passwd=$(randpass 6) 30 | echo $passwd | passwd --stdin tomcat 31 | echo $passwd > /tmp/pass.log 32 | -------------------------------------------------------------------------------- /chaper04/subshell_02.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | #描述(Description):多级子Shell演示示例. 3 | #子Shell会继承父Shell的绝大多数环境,但父Shell无法读取子Shell的环境. 4 | 5 | hi="hello" 6 | echo "+++++++++++++++" 7 | echo "+ 我是父Shell +" 8 | echo "+++++++++++++++" 9 | echo "bash_subshll=$BASH_SUBSHELL." 10 | 11 | #通过()开启子Shell. 12 | ( 13 | echo -e "\t+++++++++++++++" 14 | echo -e "\t+ 进入子Shell +" 15 | echo -e "\t+++++++++++++++" 16 | echo -e "\tbash_subshll=$BASH_SUBSHELL." 17 | ( 18 | echo -e "\t\t+++++++++++++++" 19 | echo -e "\t\t+ 进入子Shell +" 20 | echo -e "\t\t+++++++++++++++" 21 | echo -e "\t\tbash_subshll=$BASH_SUBSHELL." 22 | pstree | grep subshell 23 | ) 24 | ) 25 | 26 | echo "+++++++++++++++" 27 | echo "+ 返回父Shell +" 28 | echo "+++++++++++++++" 29 | echo "bash_subshll=$BASH_SUBSHELL." 30 | -------------------------------------------------------------------------------- /chaper04/subshell_01.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | #描述(Description):子Shell演示示例. 3 | #子Shell会继承父Shell的绝大多数环境,但父Shell无法读取子Shell的环境. 4 | 5 | hi="hello" 6 | echo "+++++++++++++++" 7 | echo "+ 我是父Shell +" 8 | echo "+++++++++++++++" 9 | echo "PWD=$PWD." 10 | echo "bash_subshll=$BASH_SUBSHELL." 11 | 12 | #通过()开启子Shell. 13 | ( 14 | sub_hi="I am a subshell" 15 | echo -e "\t+++++++++++++++" 16 | echo -e "\t+ 进入子Shell +" 17 | echo -e "\t+++++++++++++++" 18 | echo -e "\tPWD=$PWD." 19 | echo -e "\tbash_subshll=$BASH_SUBSHELL." 20 | echo -e "\thi=$hi." 21 | echo -e "\tsub_hi=$sub_hi." 22 | cd /etc;echo -e "\tPWD=$PWD" 23 | ) 24 | 25 | echo "+++++++++++++++" 26 | echo "+ 返回父Shell +" 27 | echo "+++++++++++++++" 28 | echo "PWD=$PWD." 29 | echo "hi=$hi." 30 | echo "sub_hi=$sub_hi." 31 | echo "bash_subshll=$BASH_SUBSHELL." 32 | -------------------------------------------------------------------------------- /chaper02/if_demo1.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | #read -p "请输入用户名:" user 3 | #read -s -p "请输入密码:" pass 4 | #if [ ! -z "$user" ];then 5 | # useradd "$user" 6 | #fi 7 | #if [ ! -z "$pass" ];then 8 | # echo "$pass" | passwd --stdin "$user" 9 | #fi 10 | # 11 | #read -p "请输入用户名:" user 12 | #read -s -p "请输入密码:" pass 13 | #if [ ! -z "$user" ];then 14 | # if [ ! -z "$pass" ];then 15 | # useradd $user 16 | # echo "$pass" | passwd --stdin "$user" 17 | # fi 18 | #fi 19 | # 20 | read -p "请输入用户名:" user 21 | read -s -p "请输入密码:" pass 22 | if [[ ! -z "$user" && ! -z "$pass" ]];then 23 | useradd "$user" 24 | echo "$pass" | passwd --stdin "$user" 25 | fi 26 | # 27 | #read -p "请输入用户名:" user 28 | #read -s -p "请输入密码:" pass 29 | #if [ ! -z "$user" ] && [ ! -z "$pass" ];then 30 | # useradd "$user" 31 | # echo "$pass" | passwd --stdin "$user" 32 | #fi 33 | -------------------------------------------------------------------------------- /chaper03/check_http_curl.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | #功能描述(Description):使用curl访问具体的HTTP页面,检测HTTP状态码 3 | #连续测试3次都失败则发送邮件报警. 4 | 5 | #curl命令选项说明: 6 | #-m设置超时时间 7 | #-s设置静默连接 8 | #-o下载数据另存为 9 | #-w返回附加信息,HTTP状态码 10 | 11 | url=http://192.168.4.5/index.html 12 | date=$(date +"%Y-%m-%d %H:%M:%S") 13 | mail_to="root@localhost" 14 | mail_subject="http_warning" 15 | fail_times=0 16 | for i in 1 2 3 17 | do 18 | status_code=$(curl -m 3 -s -o /dev/null -w %{http_code} $url) 19 | #使用<<-重定向可以忽略tab键缩进的内容,代码可读性更好. 20 | if [ $status_code -ne 200 ];then 21 | let fail_times++ 22 | fi 23 | sleep 1 24 | done 25 | if [ $fail_times -eq 3 ];then 26 | mail -s $mail_subject $mail_to <<- EOF 27 | 检测时间为:$date 28 | $url页面异常,服务器返回状态码:${status_code}. 29 | 请尽快排查异常. 30 | EOF 31 | else 32 | cat >> /var/log/http_check.log <<- EOF 33 | $date "$url 页面访问正常." 34 | EOF 35 | fi 36 | -------------------------------------------------------------------------------- /chaper04/multi_ping_v3.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | #Version:3.0 3 | #功能描述(Description):控制进程数量的ping测试脚本. 4 | #使用wait命令等待所有子进程结束后再退出脚本. 5 | 6 | num=10 #控制进程数量. 7 | net="192.168.4" 8 | pipefile="/tmp/multiping_$$.tmp" 9 | 10 | multi_ping() { 11 | ping -c2 -i0.2 -W1 $1 &>/dev/null 12 | if [ $? -eq 0 ];then 13 | echo "$1 is up." 14 | else 15 | echo "$1 is down." 16 | fi 17 | } 18 | 19 | #创建命名管道文件,创建其文件描述符,通过重定向导入数据到管道文件中. 20 | mkfifo $pipefile 21 | exec 12<>$pipefile 22 | for i in `seq $num` 23 | do 24 | echo "" >&12 & 25 | done 26 | 27 | #通过循环反复调用函数并将其放入后台并行执行. 28 | #成功读取命名管道中的数据后开启新的进程. 29 | #所有内容读取完后read被阻塞,无法再启动新进程. 30 | #等待前面启动的进程结束后,继续往管道文件中写入数据,释放阻塞,再次开启新的进程. 31 | for j in {1..254} 32 | do 33 | read -u12 34 | { 35 | multi_ping $net.$j 36 | echo "" >&12 37 | } & 38 | done 39 | wait 40 | rm -rf $pipfile 41 | -------------------------------------------------------------------------------- /chaper06/tmooc.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | #功能描述(Description)编写脚本抓取单个网页中的图片数据. 3 | 4 | #需要抓取数据的网页链接与种子URL文件名. 5 | page="http://www.tmooc.cn" 6 | URL="/tmp/spider_$$.txt" 7 | 8 | #将网页源代码保存到文件中. 9 | curl -s http://www.tmooc.cn/ > $URL 10 | 11 | #对文件进行过滤和清洗,获取需要的种子URL链接. 12 | echo -e "\033[32m正在获取种子URL,请稍后...\033[0m" 13 | sed -i '//dev/null; 20 | then 21 | yum -y install wget 22 | fi 23 | 24 | #利用循环批量下载所有图片数据. 25 | #wget为下载工具,其参数选项描述如下: 26 | # -P指定将数据下载到特定目录(prefix). 27 | # -c支持断点续传(continue). 28 | # -q不显示下载过程(quiet). 29 | echo -e "\033[32m正在批量下载种子数据,请稍后...\033[0m" 30 | for i in $(cat $URL) 31 | do 32 | wget -P /tmp/ -c -q $i 33 | done 34 | 35 | #删除临时种子列表文件. 36 | rm -rf $URL 37 | -------------------------------------------------------------------------------- /chaper02/score.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | #################################### 3 | #积分<=30:初学乍练 4 | #积分31-60:初窥门径 5 | #积分61-70:略有小成 6 | #积分71-80:炉火纯青 7 | #积分81-90:登封造极 8 | #积分>90:笑傲江湖 9 | ################################### 10 | 11 | read -p "请输入论坛积分:" score 12 | if [[ $score -gt 90 ]];then 13 | echo "笑傲江湖." 14 | elif [[ $score -gt 80 ]];then 15 | echo "登峰造极." 16 | elif [[ $score -gt 70 ]];then 17 | echo "炉火纯青." 18 | elif [[ $score -gt 60 ]];then 19 | echo "略有小成." 20 | elif [[ $score -gt 30 ]];then 21 | echo "初窥门径." 22 | else 23 | echo "初学乍练." 24 | fi 25 | 26 | #或者下面的排序方式也可以 27 | #if [ $score -le 30 ];then 28 | # echo "初学乍练." 29 | #elif [ $score -le 60 ];then 30 | # echo "初窥门径." 31 | #elif [ $score -le 70 ];then 32 | # echo "略有小成." 33 | #elif [ $score -le 80 ];then 34 | # echo "炉火纯青." 35 | #elif [ $score -le 90 ];then 36 | # echo "登封造极." 37 | #else 38 | # echo "笑傲江湖." 39 | #fi 40 | -------------------------------------------------------------------------------- /chaper03/IFS-demo.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | #功能描述(Description):IFS对循环影响的演示. 3 | 4 | #因为使用默认IFS的值,所以按空格为分隔符,X变量有4个值,for循环4次. 5 | echo -e "\033[32m案例1:未自定义IFS,对X="a b c d"循环4次结束.\033[0m" 6 | X="a b c d" 7 | for i in $X 8 | do 9 | echo "I am $i." 10 | done 11 | echo 12 | 13 | #备份IFS分隔符 14 | OLD_IFS="$IFS" 15 | #定义分隔符为分号,而X变量的值又没有分号分隔的数据,因此for仅会循环1次. 16 | echo -e "\033[32m案例2:自定义IFS为分号,对X="1 2 3 4"循环1次结束.\033[0m" 17 | IFS=";" 18 | X="1 2 3 4" 19 | for i in $X 20 | do 21 | echo "I am $i." 22 | done 23 | echo 24 | 25 | #定义分隔符为分号,X变量的值也使用分号分隔,因此循环了4次,每次循环输出一个名字. 26 | echo -e "\033[32m案例3:自定义IFS为分号,对X='Jacob;Rose;Vicky;Rick'循环4次结束.\033[0m" 27 | IFS=";" 28 | X="Jacob;Rose;Vicky;Rick" 29 | for i in $X 30 | do 31 | echo "I am $i." 32 | done 33 | echo 34 | 35 | #定义多个分隔符,X变量的值也使用多个分隔符分隔. 36 | #多个分隔符为或者关系,即使用分号或者句点或者冒号为分隔符.最终循环次数为4次. 37 | echo -e "\033[32m案例4:自定义IFS为:分号|句点|冒号,对X=Jacob;Rose.Vicky:Rick循环4次结束.\033[0m" 38 | IFS=";.:" 39 | X="Jacob;Rose.Vicky:Rick" 40 | for i in $X 41 | do 42 | echo "I am $i." 43 | done 44 | echo 45 | -------------------------------------------------------------------------------- /chaper01/calc.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | #计算1+2+3...+n的和,可以使用n*(n+1)/2公式快速计算结果 3 | read -p "请输入一个正整数:" num 4 | sum=$[num*(num+1)/2] 5 | echo -e "\033[32m$num以内整数的总和是:$sum\033[0m" 6 | 7 | #使用三角形的底边和高计算面积:A=1/2bh 8 | read -p "请输入三角形底边长度:" bottom 9 | read -p "请输入三角形高度:" hight 10 | A=$(echo "scale=1;1/2*$bottom*$hight" | bc) 11 | echo -e "\033[32m三角形面积是:$A\033[0m" 12 | 13 | #梯形面积:(上底+下底)*高/2 14 | read -p "请输入梯形上底:" a 15 | read -p "请输入梯形下底:" b 16 | read -p "请输入梯形高度:" h 17 | A=$(echo "scale=2;($a+$b)*$h/2" | bc) 18 | echo -e "\033[32m梯形面积是:$A\033[0m" 19 | 20 | 21 | #使用A=πr^2计算圆的面积,取2位小数π=3.14 22 | read -p "请输入圆的半径:" r 23 | A=$(echo "scale=2;3.14*$r^2" | bc) 24 | echo -e "\033[32m圆的面积是:$A\033[0m" 25 | 26 | echo "3282820KiB等于多少GiB?" 27 | G=$(echo "32828920/1024/1024" | bc) 28 | echo -e "\003[32m答案${G}G\033[0m" 29 | #注意使用{}防止变量名歧义 30 | 31 | #时间格式转化 32 | read -p "请输入秒数:" sec 33 | ms=$[sec*1000] 34 | echo -e "\033[32m$sec秒=$ms毫秒\033[0m" 35 | us=$[sec*1000000] 36 | echo -e "\033[32m$sec秒=$us微秒\033[0m" 37 | hour=$(echo "scale=2;$sec/60/60"|bc) 38 | echo -e "\033[32m$sec秒=$hour小时\033[0m" 39 | 40 | -------------------------------------------------------------------------------- /chaper06/config_sshd.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | #功能描述(Description):修改SSHD配置文件,提升SSH安全性. 3 | 4 | config_file="/etc/ssh/sshd_config" 5 | PORT=12345 6 | 7 | #将默认端口号修改为自定义端口号. 8 | if grep -q "^Port" $config_file;then 9 | sed -i "/^Port/c Port $PORT" $config_file 10 | else 11 | echo "Port $PORT" >> $config_file 12 | fi 13 | 14 | #禁止root远程登陆SSH服务器. 15 | if grep -q "^PermitRootLogin" $config_file;then 16 | sed -i '/^PermitRootLogin/s/yes/no/' $config_file 17 | else 18 | sed -i '$a PermitRootLogin no' $config_file 19 | fi 20 | 21 | #禁止使用密码远程登陆SSH服务器. 22 | if grep -q "^PasswordAuthentication" $config_file;then 23 | sed -i '/^PasswordAuthentication/s/yes/no/' $config_file 24 | else 25 | sed -i '$a PasswordAuthentication no' $config_file 26 | fi 27 | 28 | #禁止X11图形转发功能. 29 | if grep -q "^X11Forwarding" $config_file;then 30 | sed -i '/^X11Forwarding/s/yes/no/' $config_file 31 | else 32 | sed -i '$a X11Forwarding no' $config_file 33 | fi 34 | 35 | #禁止DNS查询. 36 | if grep -q "^UseDNS" $config_file;then 37 | sed -i '/^UseDNS/s/yes/no/' $config_file 38 | else 39 | sed -i '$a UseDNS no' $config_file 40 | fi 41 | 42 | -------------------------------------------------------------------------------- /chaper02/menu.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | #描述:定义功能菜单,使用case语句判断用户选择的菜单项,实现对应的功能. 3 | 4 | clear 5 | echo -e "\033[42m---------------------------------\033[0m" 6 | echo -e "\e[2;10H这里是菜单\t\t#" 7 | echo -e "#\e[32m 1.查看网卡信息\e[0m #" 8 | echo -e "#\e[33m 2.查看内存信息\e[0m #" 9 | echo -e "#\e[34m 3.查看磁盘信息\e[0m #" 10 | echo -e "#\e[35m 4.查看CPU信息\e[0m #" 11 | echo -e "#\e[36m 5.查看账户信息\e[0m #" 12 | echo -e "\033[42m---------------------------------\033[0m" 13 | echo 14 | read -p "请输入选项[1-5]:" key 15 | case $key in 16 | 1) 17 | ifconfig |head -2;; 18 | 2) 19 | mem=$(free |grep Mem |tr -s " " | cut -d" " -f7) 20 | echo "本机内存剩余容量为:${mem}K.";; 21 | 3) 22 | root_free=$(df | grep /$ | tr -s " " | cut -d " " -f4) 23 | echo "本机根分区剩余容量为:${root_free}K.";; 24 | 4) 25 | cpu=$(uptime | tr -s " " | cut -d" " -f13) 26 | echo "本机CPU 15分钟的平均负载为:$cpu.";; 27 | 5) 28 | login_number=$(who | wc -l) 29 | total_number=$(cat /etc/passwd | wc -l) 30 | echo "当前系统账户为$USER." 31 | echo "当前登陆系统的账户数量为:$login_number." 32 | echo "当前系统中总用户数量为:$total_number.";; 33 | *) 34 | echo "输入有误,超出1-5的范围.";; 35 | esac 36 | -------------------------------------------------------------------------------- /chaper04/proc_buble_sort.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | #功能描述(Description):根据进程所占物理内存的大小对进程排序. 3 | 4 | #保存当前系统所有进程的名称及其所占物理内存大小的数据到临时文件. 5 | tmpfile="/tmp/procs_mem_$$.txt" 6 | ps --no-headers -eo comm,rss > $tmpfile 7 | 8 | 9 | #定义函数实现冒泡排序. 10 | #使用i控制进行几轮的比较,使用j控制每轮比较的次数. 11 | #使用变量len读取数组个数,根据内存大小排序,并且调整对应的进程名称的顺序. 12 | bubble() { 13 | local i j 14 | local len=$1 15 | for ((i=1;i<=$[len-1];i++)) 16 | do 17 | for ((j=1;j<=$[len-i];j++)) 18 | do 19 | if [ ${mem[j]} -gt ${mem[j+1]} ];then 20 | tmp=${mem[j]} 21 | mem[$j]=${mem[j+1]} 22 | mem[j+1]=$tmp 23 | tmp=${name[j]} 24 | name[$j]=${name[j+1]} 25 | name[j+1]=$tmp 26 | fi 27 | done 28 | done 29 | echo "排序后进程序列:" 30 | echo "---------------------------------------------" 31 | echo "${name[@]}" 32 | echo "---------------------------------------------" 33 | echo "${mem[@]}" 34 | echo "---------------------------------------------" 35 | } 36 | 37 | #使用两个数组(name,mem)分别保存进程名称和进程所占内存大小. 38 | i=1 39 | while read proc_name proc_mem 40 | do 41 | name[$i]=$proc_name 42 | mem[$i]=$proc_mem 43 | let i++ 44 | done < $tmpfile 45 | rm -rf $tmpfile 46 | #调用函数,根据内存大小对数据进行排序. 47 | bubble ${#mem[@]} 48 | -------------------------------------------------------------------------------- /chaper06/roll.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | #功能描述(Description):随机点名抽奖器. 3 | 4 | #按Ctrl+C时:恢复光标,恢复终端属性,清屏,退出脚本. 5 | #防止程序意外中断导致的终端混乱. 6 | trap 'tput cnorm;stty $save_property;clear;exit' 2 7 | 8 | #定义变量:人员列表文件名,文件的行数,屏幕的行数,屏幕的列数. 9 | name_file="name.txt" 10 | line_file=$(sed -n '$=' $name_file) 11 | line_screen=`tput lines` 12 | column_screen=`tput cols` 13 | 14 | #设置终端属性 15 | save_property=$(stty -g) #保存当前终端所有属性. 16 | tput civis #关闭光标. 17 | 18 | #随机抽取一个人名(随机点名). 19 | while : 20 | do 21 | tmp=$(sed -n "$[RANDOM%line_file+1]p" $name_file) 22 | #随机获取文件的某一行人名. 23 | tput clear #清屏. 24 | tput cup $[line_screen/4] $[column_screen/4] 25 | echo -e "\033[3;5H 随机点名器(按P停止): " 26 | echo -e "\033[4;5H#############################" 27 | echo -e "\033[5;5H# #" 28 | echo -e "\033[6;5H#\t\t$tmp\t\t#" 29 | echo -e "\033[7;5H# #" 30 | echo -e "\033[8;5H#############################" 31 | sleep 0.1 32 | stty -echo 33 | read -n1 -t0.1 input 34 | if [[ $input == "p" || $input == "P" ]];then 35 | break 36 | fi 37 | done 38 | tput cnorm #恢复光标. 39 | stty $save_property #恢复终端属性. 40 | -------------------------------------------------------------------------------- /chaper06/kernel.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | #功能描述(Description):编写脚本修改Linux内核启动参数. 3 | 4 | #使用传统的eth0,eth1风格的网卡名称. 5 | sed -i '/CMDLINE/s/"/ biosdevname=0 net.ifnames=0"/2' /etc/default/grub 6 | 7 | #禁用SELinux. 8 | sed -i '/CMDLINE/s/"/ selinux=0"/2' /etc/default/grub 9 | 10 | #开启内存大页(HugePage),调整大页容量为4M,大页个数为100个. 11 | #可以/proc/meminfo查看大页的信息. 12 | sed -i '/CMDLINE/s/"/ hugepagesz=4M hugepages=100"/2' /etc/default/grub 13 | 14 | #禁用IPv6网络. 15 | sed -i '/CMDLINE/s/"/ ipv6.disable=1"/2' /etc/default/grub 16 | 17 | #配置Grub密码:用户名(root),密码(123456). 18 | #手动执行grub2-mkpasswd-pbkdf2获取密码的加密信息,然后将密码写入grub配置文件. 19 | #下面是123456的密文信息. 20 | #grub.pbkdf2.sha512.10000.BE5B2CAB43F2F513ED696C5EB15A8072F0744F123CBA0C16C4285C80507E1192236EFB3CBF21A23D384F1C63AD65DCEE1676ECE5A8DB065741E3CBD58E9C256F.163A3FF46D1935CB9A08FC42FCCC7285E34B789CC006B94195DF42EC53458277C1BBA6A26BD8460C15E6986001EBE10F5F3D6F81E4ED8893AACBFE3351F3A85F 21 | echo '#!/bin/sh -e 22 | cat << EOF 23 | set superusers="root" 24 | export superusers 25 | password_pbkdf2 root grub.pbkdf2.sha512.10000.BE5B2CAB43F2F513ED696C5EB15A8072F0744F123CBA0C16C4285C80507E1192236EFB3CBF21A23D384F1C63AD65DCEE1676ECE5A8DB065741E3CBD58E9C256F.163A3FF46D1935CB9A08FC42FCCC7285E34B789CC006B94195DF42EC53458277C1BBA6A26BD8460C15E6986001EBE10F5F3D6F81E4ED8893AACBFE3351F3A85F 26 | EOF' > /etc/grub.d/01_users 27 | 28 | #利用grub2-mkconfig生成新的grub配置文件/boot/grub2/grub.cfg. 29 | grub2-mkconfig -o /boot/grub2/grub.cfg 30 | -------------------------------------------------------------------------------- /chaper04/quick_sort.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | #功能描述(Description):采用分治思想的冒泡算法改进算法快速排序(快排). 3 | 4 | #初始化一个数组. 5 | num=(5 3 8 4 7 9 2) 6 | 7 | #定义一个可以递归调用的快速排序的函数. 8 | quick_sort(){ 9 | #先判断需要比较的数字个数,$1是数组最左边的坐标,$2是数组最右边的坐标. 10 | #左边的坐标要小于右边坐标,否则表示需要排序的数字只有一个,不需要排序可以直接退出函数. 11 | if [ $1 -ge $2 ];then 12 | return 13 | fi 14 | 15 | #定义局部变量,base为基准数字,这里我们选择的是最左边的数字num[$1]. 16 | #i表示左边的坐标,right表示右边的坐标(也可以使用i和j表示左右坐标). 17 | local base=${num[$1]} 18 | local left=$1 19 | local right=$2 20 | 21 | #把要排序的数字序列中,比基准数大的放右边,比基准数小的放左边. 22 | while [ $left -lt $right ] 23 | do 24 | #right向左移动,找比基准数(base)小的元素. 25 | while [[ ${num[right]} -ge $base && $left -lt $right ]] 26 | do 27 | let right-- 28 | done 29 | #left向右移动,找比基准数(base)大的元素. 30 | while [[ ${num[left]} -le $base && $left -lt $right ]] 31 | do 32 | let left++ 33 | done 34 | #将left坐标元素和right坐标元素交换. 35 | if [ $left -lt $right ];then 36 | local tmp=${num[$left]} 37 | num[$left]=${num[right]} 38 | num[$right]=$tmp 39 | fi 40 | done 41 | 42 | #将基准数字与left坐标元素交换. 43 | num[$1]=${num[left]} 44 | num[left]=$base 45 | 46 | #递归调用快速排序算法,对i左边的元素实施快速排序工作. 47 | quick_sort $1 $[left-1] 48 | #递归调用快速排序算法,对i右边的元素实施快速排序工作. 49 | quick_sort $[left+1] $2 50 | } 51 | 52 | #调用函数对数组排序,排序后输出数组的所有元素. 53 | quick_sort 0 ${#num[@]} 54 | echo ${num[*]} 55 | -------------------------------------------------------------------------------- /chaper02/nginx: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # chkconfig: 2345 90 98 3 | #描述:CentOS6的Nginx服务启动脚本. 4 | #备注:CentOS7向下兼容CentOS6的启动脚本. 5 | #暂时没有使用函数功能,如果使用函数脚本会更加简洁. 6 | 7 | nginx="/usr/local/nginx/sbin/nginx" 8 | pidfile="/usr/local/nginx/logs/nginx.pid" 9 | 10 | case $1 in 11 | start) 12 | if [ -f $pidfile ];then 13 | echo -e "\033[91mNginx is already running...\033[0m" 14 | exit 15 | else 16 | $nginx && echo -e "\033[32mNginx is already running...\033[0m" 17 | fi;; 18 | stop) 19 | if [ ! -f $pidfile ];then 20 | echo -e "\033[91mNginx is already stoped.\033[0m" 21 | exit 22 | else 23 | $nginx -s stop && echo -e "\033[32mNginx is stoped.\033[0m" 24 | fi;; 25 | restart) 26 | if [ ! -f $pidfile ];then 27 | echo -e "\033[91mNginx is already stoped.\033[0m" 28 | echo -e "\033[91mPlease to run Nginx first.\033[0m" 29 | exit 30 | else 31 | $nginx -s stop && echo -e "\033[32mNginx is stoped.\033[0m" 32 | fi 33 | $nginx && echo -e "\033[32mNginx is running...\033[0m" 34 | ;; 35 | status) 36 | if [ -f $pidfile ];then 37 | echo -e "\033[32mNginx is running...\033[0m" 38 | else 39 | echo -e "\033[32mNginx is stoped.\033[0m" 40 | fi;; 41 | reload) 42 | if [ ! -f $pidfile ];then 43 | echo -e "\033[91mNginx is already stoped.\033[0m" 44 | exit 45 | else 46 | $nginx -s reload && echo -e "\033[32mReload configure done.\033[0m" 47 | fi;; 48 | *) 49 | echo "Usage:$0 {start|stop|restart|status|reload}";; 50 | esac 51 | -------------------------------------------------------------------------------- /chaper02/install_nginx.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | #脚本功能描述(Description):一键源码安装Nginx软件包 3 | 4 | #定义不同的颜色属性 5 | setcolor_failure="echo -en \\033[91m" 6 | setcolor_success="echo -ne \\033[32m" 7 | setcolor_normal="echo -e \\033[0m" 8 | 9 | #判断是否以管理员身份执行脚本 10 | if [[ $UID -ne 0 ]];then 11 | $setcolor_failure 12 | echo -n "请以管理员身份运行该脚本." 13 | $setcolor_normal 14 | exit 15 | fi 16 | 17 | #判断系统中是否存在wget这个下载工具 18 | #wget使用-c选项可以开启断点续传功能 19 | if rpm --quiet -q wget ;then 20 | wget -c http://nginx.org/download/nginx-1.14.0.tar.gz 21 | else 22 | $setcolor_failure 23 | echo -n "未找到wget,请先安装该软件." 24 | $setcolor_normal 25 | exit 26 | fi 27 | 28 | #如果没有nginx账户,则脚本自动创建该账户 29 | if ! id nginx &>/dev/null ;then 30 | adduser -s /sbin/nologin nginx 31 | fi 32 | 33 | #测试是否存在正确的源码包软件 34 | if [[ ! -f nginx-1.14.0.tar.gz ]];then 35 | $setcolor_failure 36 | echo -n "未找到nginx源码包,请先正确下载该软件再试..." 37 | $setcolor_normal 38 | exit 39 | else 40 | #源码编译安装前,先安装相关依赖包 41 | #gcc:C语言编译器|pcre-devel:Perl兼容的正则表达式库 42 | #zlib-devel:gzip压缩库|openssl-devel:Openssl加密库 43 | yum -y install gcc pcre-devel zlib-devel openssl-devel 44 | clear 45 | $setcolor_success 46 | echo -n "接下来,需要花费几分钟时间源码编译安装nginx..." 47 | $setcolor_normal 48 | sleep 6 49 | tar -xf nginx-1.14.0.tar.gz 50 | #源码编译安装nginx,指定账户和组,指定安装路径,开启需要的模块,禁用不需要的模块 51 | cd nginx-1.14.0/ 52 | ./configure \ 53 | --user=nginx \ 54 | --group=nginx \ 55 | --prefix=/data/server/nginx \ 56 | --with-stream \ 57 | --with-http_ssl_module \ 58 | --with-http_stub_status_module \ 59 | --without-http_autoindex_module \ 60 | --without-http_ssi_module 61 | make 62 | make install 63 | fi 64 | if [[ -x /data/server/nginx/sbin/nginx ]];then 65 | clear 66 | $setcolor_success 67 | echo -n "一键部署nginx已经完成!" 68 | $setcolor_normal 69 | fi 70 | -------------------------------------------------------------------------------- /chaper06/guestfish.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | #功能描述(Description):使用guestfish工具修改虚拟机网卡配置文件. 3 | #脚本在不启动登陆虚拟机的情况下,直接修改虚拟机网卡的配置文件. 4 | 5 | read -p "请输入需要编辑的虚拟机名称:" vname 6 | 7 | #测试虚拟机是否为正在运行状态. 8 | if virsh domstate $vname | grep -q running ;then 9 | echo "修改虚拟机网卡配置,请先关闭虚拟机." 10 | exit 11 | fi 12 | 13 | #创建挂载点,测试挂载点是否正在被其他程序使用. 14 | mountpint="/media/$vname" 15 | [ ! -d $mountpint ] && mkdir -p $mountpint 16 | if mount | grep -q "$mountpint";then 17 | umount $mountpint 18 | fi 19 | 20 | #使用guestmount命令将虚拟机文件系统挂载到真实主机. 21 | echo "请稍后..." 22 | guestmount -i -d $vname $mountpint 23 | 24 | #读取必要的配置文件参数. 25 | vpath="etc/sysconfig/network-scripts/" 26 | read -p "请输入需要编辑的网卡名称:" devname 27 | if [ ! -f $mountpint/$vpath/ifcfg-$devname ];then 28 | echo "未找到${devname}网卡配置文件" 29 | exit 30 | fi 31 | read -p "请输入IP地址与子网掩码(如:192.168.4.1/24):" addr 32 | ipaddr=$(echo $addr | cut -d/ -f1) 33 | netmask=$(echo $addr | cut -d/ -f2) 34 | read -p "请输入默认网关:" gateway 35 | read -p "请输入DNS:" dns 36 | 37 | #修改网卡配置文件. 38 | sed -i '/BOOTPROTO/c BOOTPROTO=static' $mountpint/$vpath/ifcfg-$devname 39 | sed -i '/ONBOOT/c ONBOOT=yes' $mountpint/$vpath/ifcfg-$devname 40 | #修改IP地址. 41 | if grep -q IPADDR $mountpint/$vpath/ifcfg-$devname;then 42 | sed -i "/IPADDR/c IPADDR=$ipaddr" $mountpint/$vpath/ifcfg-$devname 43 | else 44 | echo "IPADDR=$ipaddr" >> $mountpint/$vpath/ifcfg-$devname 45 | fi 46 | #修改子网掩码. 47 | if grep -q PREFIX $mountpint/$vpath/ifcfg-$devname;then 48 | sed -i "/PREFIX/c PREFIX=$netmask" $mountpint/$vpath/ifcfg-$devname 49 | else 50 | echo "PREFIX=$netmask" >> $mountpint/$vpath/ifcfg-$devname 51 | fi 52 | #修改默认网关. 53 | if grep -q GATEWAY $mountpint/$vpath/ifcfg-$devname;then 54 | sed -i "/GATEWAY/c GATEWAY=$gateway" $mountpint/$vpath/ifcfg-$devname 55 | else 56 | echo "GATEWAY=$gateway" >> $mountpint/$vpath/ifcfg-$devname 57 | fi 58 | #修改DNS服务器. 59 | if grep -q DNS $mountpint/$vpath/ifcfg-$devname;then 60 | sed -i "/DNS/c DNS1=$dns" $mountpint/$vpath/ifcfg-$devname 61 | else 62 | echo "DNS1=$dns" >> $mountpint/$vpath/ifcfg-$devname 63 | fi 64 | 65 | #取消文件系统挂载. 66 | guestunmount $mountpint 67 | -------------------------------------------------------------------------------- /chaper07/movie.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | #功能描述(Description):编写网络爬虫,抓取网络视频下载链接. 3 | #备注:因为网站随时可能改版,因此具体的爬取数据和过滤的方法需要根据实际情况适当修订. 4 | 5 | tmpfile="/tmp/tmp_$$.txt" 6 | pagefile="/tmp/page_" 7 | moviefile="/tmp/movie_" 8 | listfile="/tmp/list.txt" 9 | 10 | #下载首页源码,并获取子页面链接列表(id=menu到/div中间的行为子页面的链接). 11 | curl -s https://www.dytt8.net > $tmpfile 12 | LANG=C sed -i '/id="menu"/,/\/div/!d' $tmpfile 13 | 14 | #上面进行数据过滤后结果如下,需要继续使用awk将多余的数据清洗掉. 15 | #awk通过-F选项指定以双引号"为分隔符. 16 | #最新影片
  • 17 | #经典影片
  • 18 | #国内电影
  • 19 | #欧美电影
  • 20 | URL=$(sed -n '/id="menu"/,/\/div/p' $tmpfile | awk -F\" '/href/&&/http/{print $2}') 21 | 22 | #清洗后结果如下: 23 | #https://www.ygdy8.net/html/gndy/dyzz/index.html 24 | #https://www.ygdy8.net/html/gndy/index.html 25 | #https://www.ygdy8.net/html/gndy/china/index.html 26 | #https://www.ygdy8.net/html/gndy/oumei/index.html 27 | 28 | #利用循环访问每个子页面,分别获取电影列表信息. 29 | echo -e "\033[32m正在抓取网站中视频数据的链接.\033[0m" 30 | echo "根据网站数据量不同,可能需要比较长的时间,请耐心等待..." 31 | x=1 32 | y=1 33 | for subpage in $URL 34 | do 35 | curl -s $subpage > $pagefile$x 36 | #过滤class="co_content8到class="x"之间的行,其他行都删除. 37 | sed -i '/class="co_content8"/,/class="x"/!d' $pagefile$x 38 | 39 | #获取具体电影的主页链接,过滤包含href的链接行,默认链接只有路径,没有网站主域名,需要使用awk修改改路径. 40 | 41 | #修改前:/html/gndy/dyzz/20190411/58451.html 42 | #修改后:http://www.ygdy8.net/html/gndy/dyzz/20190411/58451.html 43 | SUB_URL=$(awk -F[\'\"] '/ $moviefile$y 48 | sed -i '/ftp/!d' $moviefile$y 49 | #将最终过滤的视频链接保存至$listfile文件. 50 | touch $listfile 51 | awk -F\" '{print $6}' $moviefile$y >> $listfile 52 | let y++ 53 | done 54 | let x++ 55 | done 56 | rm -rf "$tmpfile" 57 | rm -rf /tmp/page_* 58 | rm -rf /tmp/movie_* 59 | -------------------------------------------------------------------------------- /chaper04/nginx_log.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | #功能描述(Description):Nginx标准日志分析脚本. 3 | #统计信息包括: 4 | #1.页面访问量PV 5 | #2.用户量UV 6 | #3.人均访问量 7 | #4.每个IP的访问次数 8 | #5.HTTP状态码统计 9 | #6.累计页面字节流量 10 | #7.热点数据 11 | 12 | GREEN_COL='\033[32m' 13 | NONE_COL='\033[0m' 14 | line='echo ++++++++++++++++++++++++++++++++++' 15 | 16 | read -p "请输入日志文件:" logfile 17 | echo 18 | 19 | #统计页面访问量(PV). 20 | PV=$(cat $logfile | wc -l) 21 | 22 | #统计用户数量(UV). 23 | UV=$(cut -f1 -d' ' $logfile | sort | uniq | wc -l) 24 | 25 | #统计人均访问次量. 26 | Average_PV=$(echo "scale=2;$PV/$UV" | bc) 27 | 28 | #统计每个IP的访问次数. 29 | declare -A IP 30 | while read ip other 31 | do 32 | let IP[$ip]+=1 33 | done < $logfile 34 | 35 | #统计各种HTTP状态码的个数,如404报错的次数,500错误的次数等. 36 | declare -A STATUS 37 | while read ip dash user time zone method file protocol code size other 38 | do 39 | let STATUS[$code]++ 40 | done < $logfile 41 | 42 | #统计累计网页字节大小. 43 | while read ip dash user time zone method file protocol code size other 44 | do 45 | let Body_size+=$size 46 | done < $logfile 47 | 48 | 49 | #统计热点数据 50 | declare -A URI 51 | while read ip dash user time zone method file protocol code size other 52 | do 53 | let URI[$file]++ 54 | done < $logfile 55 | 56 | echo -e "\033[91m\t日志分析数据报表\033[0m" 57 | 58 | #显示PV与UV访问量,平均用户访问量. 59 | $line 60 | echo -e "累计PV量: $GREEN_COL$PV$NONE_COL" 61 | echo -e "累计UV量: $GREEN_COL$UV$NONE_COL" 62 | echo -e "平均用户访问量: $GREEN_COL$Average_PV$NONE_COL" 63 | 64 | #显示累计网页字节数. 65 | $line 66 | echo -e "累计访问字节数: $GREEN_COL$Body_size$NONE_COL Byte" 67 | 68 | #显示指定的HTTP状态码数量. 69 | $line 70 | for i in 200 404 500 71 | do 72 | if [ ${STATUS[$i]} ];then 73 | echo -e "$i状态码次数:$GREEN_COL ${STATUS[$i]} $NONE_COL" 74 | else 75 | echo -e "$i状态码次数:$GREEN_COL 0 $NONE_COL" 76 | fi 77 | done 78 | 79 | #显示每个IP的访问次数. 80 | $line 81 | for i in ${!IP[@]} 82 | do 83 | printf "%-15s的访问次数为: $GREEN_COL%s$NONE_COL\n" $i ${IP[$i]} 84 | done 85 | echo 86 | 87 | #显示访问量大于500的URI 88 | echo -e "$GREEN_COL访问量大于500的URI:$NONE_COL" 89 | for i in "${!URI[@]}" 90 | do 91 | if [ ${URI["$i"]} -gt 500 ];then 92 | echo "-----------------------------------" 93 | echo "$i" 94 | echo "${URI[$i]}次" 95 | echo "-----------------------------------" 96 | fi 97 | done 98 | -------------------------------------------------------------------------------- /chaper07/nginx_log.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | #功能描述(Description):Nginx标准日志分析脚本. 3 | #统计信息包括: 4 | #1.页面访问量PV 5 | #2.用户量UV 6 | #3.人均访问量 7 | #4.每个IP的访问次数 8 | #5.HTTP状态码统计 9 | #6.累计页面字节流量 10 | #7.热点数据 11 | 12 | GREEN_COL='\033[32m' 13 | NONE_COL='\033[0m' 14 | line='echo ++++++++++++++++++++++++++++++++++' 15 | 16 | read -p "请输入日志文件:" logfile 17 | echo 18 | 19 | #判断日志文件是否存在. 20 | if [ ! -f $logfile ];then 21 | echo "$logfile文件不存在." 22 | exit 23 | fi 24 | 25 | #统计页面访问量(PV). 26 | PV=$(sed -n '$=' $logfile) 27 | 28 | #统计用户数量(UV). 29 | UV=$(awk '{IP[$1]++} END{ print length(IP)}' $logfile) 30 | 31 | #统计人均访问次量. 32 | Average_PV=$(echo "scale=2;$PV/$UV" | bc) 33 | 34 | #统计每个IP的访问次数. 35 | #sort选项: 36 | # -n可以按数字排序,默认为升序. 37 | # -r为倒序排列,降序. 38 | # -k可以指定按照第几列排序,k3按照第三列排序. 39 | IP=$(awk '{IP[$1]++} END{ for(i in IP){print i,"\t的访问次数为:",IP[i]}"\r"}' $logfile | sort -rn -k3) 40 | 41 | #统计各种HTTP状态码的个数,如404报错的次数,500错误的次数等. 42 | STATUS=$(awk '{IP[$9]++} END{ for(i in IP){print i"状态码的次数:",IP[i]}"\r"}' $logfile | sort -rn -k2) 43 | 44 | #统计累计网页字节大小. 45 | Body_size=$(awk '{SUM+=$10} END{ print SUM }' $logfile) 46 | 47 | 48 | #统计热点数据,将所有页面的访问次数写入数组, 49 | #如果访问次数大于500,则显示该页面文件名与具体访问次数. 50 | # awk ' \ 51 | # {IP[$7]++} \ 52 | # END{ \ 53 | # for(i in IP){ \ 54 | # if(IP[i]>=500) { \ 55 | # print i"的访问次数:",IP[i] \ 56 | # } \ 57 | # } \ 58 | # }' $logfile 59 | URI=$(awk '{IP[$7]++} END{ for(i in IP){ if(IP[i]>=500) {print i"的访问次数:",IP[i]}}}' $logfile) 60 | 61 | 62 | #从这里开始显示前面获取的各种数据. 63 | echo -e "\033[91m\t日志分析数据报表\033[0m" 64 | 65 | #显示PV与UV访问量,平均用户访问量. 66 | $line 67 | echo -e "累计PV量: $GREEN_COL$PV$NONE_COL" 68 | echo -e "累计UV量: $GREEN_COL$UV$NONE_COL" 69 | echo -e "平均用户访问量: $GREEN_COL$Average_PV$NONE_COL" 70 | 71 | #显示累计网页字节数. 72 | $line 73 | echo -e "累计访问字节数: $GREEN_COL$Body_size$NONE_COL Byte" 74 | 75 | #显示指定的HTTP状态码数量. 76 | #变量STATUS的值为多行数据,包含有换行符. 77 | #注意:调用变量时必须使用双引号!否则将无法处理换行符号. 78 | $line 79 | echo "$STATUS" 80 | 81 | #显示每个IP的访问次数. 82 | $line 83 | echo "$IP" 84 | 85 | #显示访问量大于500的URI 86 | echo -e "$GREEN_COL访问量大于500的URI:$NONE_COL" 87 | echo "$URI" 88 | -------------------------------------------------------------------------------- /chaper04/puzzle.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | #功能描述(Description):文字组合拼接游戏. 3 | 4 | tmpfile="/tmp/puzzle-$$.txt" 5 | #正确的英文原文 6 | cat > $tmpfile << EOF 7 | The best hearts are always the bravest. 8 | History teaches, but it has no pupils. 9 | Dreams are the food of human progress. 10 | Questions can't change the truth. But they give it motion. 11 | We can only see a short distance ahead, but we can see plenty there that needs to be done. 12 | Endeavor to see the good in every situation. 13 | Life is not a problem to be solved, but a reality to be experienced. 14 | Love is composed of a single soul inhabiting two bodies. 15 | Everyone can rise above their circumstances and achieve success if they are dedicated to and passionate about what they do. 16 | Nothing is impossible, the word itself says I'm possible! 17 | Life isn't about finding yourself. Life is about creating yourself. 18 | EOF 19 | 20 | #定义函数:随机读取文件的行. 21 | get_line(){ 22 | local num=$[RANDOM%`cat $1 | wc -l`+1] 23 | line=`head -$num $1 | tail -1` 24 | } 25 | 26 | #定义函数:将文件行中的所有单词拆散并保存到数组word中. 27 | break_line(){ 28 | index=0 29 | for i in $line 30 | do 31 | word[$index]=$i 32 | let index++ 33 | done 34 | } 35 | 36 | #定义函数:随机输出数组中所有元素的值. 37 | get_word(){ 38 | while : 39 | do 40 | #统计数组最大值,使用随机数对最大值取余,例如:数组中有8个单词,则对8取余(0-7). 41 | local max=${#word[@]} 42 | local num=$[RANDOM%max] 43 | #将已经提取的随机数组下标保存到tmp临时变量,如果下标已经在tmp中则不再显示该下标的值. 44 | #如果随机下标没有在tmp变量中,则显示对应数组下标的值(也就是某个单词). 45 | if ! echo $tmp | grep -qw $num ;then 46 | echo -n "${word[num]} " 47 | local tmp="$tmp $num" 48 | fi 49 | #判断当所有下标都提取完成后退出while循环. 50 | if [ `echo $tmp | wc -w` -eq ${#word[@]} ];then 51 | break 52 | fi 53 | done 54 | echo;echo 55 | } 56 | 57 | #调用函数完成单词拼接游戏. 58 | get_line $tmpfile 59 | break_line 60 | clear 61 | echo "-------------------------------------------------" 62 | echo -e "\033[34m尝试将下面的单词重新组合为一个完整的句子:\033[0m" 63 | echo "-------------------------------------------------" 64 | get_word 65 | 66 | #读取用户的输入信息,并通过tr命令将用户输入的多个空格压缩为一个空格(去除重复的空格). 67 | read -p "请输入:" input 68 | input=`echo $input | tr -s ' '` 69 | 70 | #判断用户输入的信息是否正确. 71 | if grep -q "^$input$" $tmpfile ;then 72 | echo -e "\033[32m完全正确,恭喜!\033[0m" 73 | else 74 | echo -e "\033[36mOops,再接再厉!\033[0m" 75 | fi 76 | rm -rf $tmpfile 77 | -------------------------------------------------------------------------------- /chaper05/countdown.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | #功能描述(Description):时间倒计时. 3 | 4 | #使用Ctrl+C中断脚本或者倒计时结束时显示光标. 5 | trap 'tput cnorm;exit' INT EXIT 6 | 7 | #定义数组变量,该数组有9行9个元素,每行是1个元素,每一个数字宽度占用12列. 8 | #循环对数组9个元素进行字串截取,每一个元素提取0-11位就是数字0, 9 | #循环对数组9个元素进行字串截取,每一个元素提取12-23位就是数字1,依此类推. 10 | number=( 11 | ' 0000000000 111 2222222222 3333333333 44 44 5555555555 6666666666 777777777 888888888 9999999999 ' 12 | ' 00 00 11111 22 33 44 44 55 66 77 77 88 88 99 99 ' 13 | ' 00 00 111111 22 33 44 44 55 66 77 77 88 88 99 99 ' 14 | ' 00 00 11 22 33 44 44 55 66 77 88 88 99 99 ' 15 | ' 00 00 11 2222222222 3333333333 44444444444 5555555555 6666666666 77 888888888 9999999999 ' 16 | ' 00 00 11 22 33 44 55 66 66 77 88 88 99 ' 17 | ' 00 00 11 22 33 44 55 66 66 77 88 88 99 ' 18 | ' 00 00 11 22 33 44 55 66 66 77 88 88 99 ' 19 | ' 0000000000 1111111111 2222222222 3333333333 44 5555555555 6666666666 77 888888888 9999999999 ' 20 | ) 21 | 22 | #通过位置变量获取需要倒计时的时间,并将分钟转换为秒. 23 | translate_time(){ 24 | if [ -z "$1" ];then 25 | echo "$0 需要时间参数n" 26 | echo "n:表示需要倒计时的时间,单位为分钟." 27 | exit 28 | fi 29 | sec=$[$1*60] #将分钟转换为秒. 30 | } 31 | 32 | #定义函数:打印数组中的某一个数字. 33 | print_time(){ 34 | #从第几个位置开始提取数组元素,数字0就从0开始,数字1就从12开始,数字2就从24开始,依此类推. 35 | begin=$[$1*12] 36 | for i in `seq 0 ${#number[@]}` #0-9的循环. 37 | do 38 | tput cup $[i+5] $2 39 | echo -en "\033[91m${number[i]:$begin:12}\033[0m" 40 | done 41 | } 42 | 43 | #每秒刷新屏幕,打印新的时间,每循环一次倒计时秒数减1. 44 | translate_time $1 45 | while : 46 | do 47 | [ $sec -lt 0 ] && exit 48 | tput civis #隐藏光标. 49 | tput clear 50 | tput cup 3 16 51 | echo -e "\e[1;32m$1分钟倒计时:\e[0m" 52 | #循环将倒计时秒数中的所有数字提取出来,显示在屏幕. 53 | for j in `seq ${#sec}` 54 | do 55 | num=`echo $sec | cut -c $j` 56 | y=$[j*16] 57 | print_time $num $y 58 | done 59 | let sec-- 60 | echo 61 | sleep 1 62 | done 63 | 64 | -------------------------------------------------------------------------------- /chaper06/movie.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | #功能描述(Description):编写网络爬虫,抓取网络视频下载链接. 3 | #备注:因为网站随时可能改版,因此具体的爬取数据和过滤的方法需要根据实际情况适当修订. 4 | 5 | tmpfile="/tmp/tmp_$$.txt" 6 | pagefile="/tmp/page_" 7 | moviefile="/tmp/movie_" 8 | listfile="/tmp/list.txt" 9 | 10 | #下载首页源码,并获取子页面链接列表. 11 | curl -s https://www.dytt8.net > $tmpfile 12 | sed -i '/^最新影片
  • 16 | #经典影片
  • 17 | #国内电影
  • 18 | #欧美电影
  • 19 | sed -i 's/ $pagefile$x 36 | #第一行之start:body content之间的所有行删除. 37 | sed -i '1,/start:body content/d' $pagefile$x 38 | #删除包含index.html的行. 39 | sed -i "/index.html/d" $pagefile$x 40 | #仅保留包含 $moviefile$y 56 | sed -i '/ftp/!d' $moviefile$y 57 | LANG=C sed -i 's/.*="//' $moviefile$y 58 | LANG=C sed -i 's/">.*//' $moviefile$y 59 | #将最终过滤的视频链接保存至$listfile文件. 60 | cat $moviefile$y >> $listfile 61 | let y++ 62 | done 63 | let x++ 64 | done 65 | sed -i '/^ftp:/!d' $listfile 66 | rm -rf $tmpfile 67 | rm -rf $pagefile 68 | rm -rf $moviefile 69 | 70 | -------------------------------------------------------------------------------- /chaper05/clock.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | #功能描述(Description):通过tput定位光标,在屏幕特定位置打印当前的计算机时间. 3 | 4 | #使用Ctrl+C中断脚本时显示光标. 5 | trap 'tput cnorm;exit' INT 6 | 7 | #定义数组变量,该数组有9行9个元素,每行是1个元素,每一个数字宽度占用12列. 8 | #循环对数组9个元素进行字串截取,每一个元素提取0-11位就是数字0, 9 | #循环对数组9个元素进行字串截取,每一个元素提取12-23位就是数字1,依此类推. 10 | number=( 11 | ' 0000000000 111 2222222222 3333333333 44 44 5555555555 6666666666 777777777 888888888 9999999999 ' 12 | ' 00 00 11111 22 33 44 44 55 66 77 77 88 88 99 99 ' 13 | ' 00 00 111111 22 33 44 44 55 66 77 77 88 88 99 99 ' 14 | ' 00 00 11 22 33 44 44 55 66 77 88 88 99 99 ' 15 | ' 00 00 11 2222222222 3333333333 44444444444 5555555555 6666666666 77 888888888 9999999999 ' 16 | ' 00 00 11 22 33 44 55 66 66 77 88 88 99 ' 17 | ' 00 00 11 22 33 44 55 66 66 77 88 88 99 ' 18 | ' 00 00 11 22 33 44 55 66 66 77 88 88 99 ' 19 | ' 0000000000 1111111111 2222222222 3333333333 44 5555555555 6666666666 77 888888888 9999999999 ' 20 | ) 21 | 22 | #获取计算机时间,并分别提取个位和十位数字. 23 | now_time(){ 24 | hour=$(date +%H) 25 | min=$(date +%M) 26 | sec=$(date +%S) 27 | 28 | hour_left=`echo $hour/10 | bc` 29 | hour_right=`echo $hour%10 | bc` 30 | min_left=`echo $min/10 | bc` 31 | min_right=`echo $min%10 | bc` 32 | sec_left=`echo $sec/10 | bc` 33 | sec_right=`echo $sec%10 | bc` 34 | } 35 | 36 | #定义函数:打印数组中的某一个数字. 37 | print_time(){ 38 | #从第几个位置开始提取数组元素,数字0就从0开始,数字1就从12开始,数字2就从24开始,依此类推. 39 | begin=$[$1*12] 40 | for i in `seq 0 ${#number[@]}` #0-9的循环. 41 | do 42 | tput cup $[i+5] $2 #定位光标 43 | echo -en "\033[32m${number[i]:$begin:12}\033[0m" 44 | done 45 | } 46 | #打印时间分隔符,echo通过\u可以支持unicode符号. 47 | #unicode编码中2588是一个方块. 48 | print_punct(){ 49 | tput cup $1 $2 50 | echo -en "\e[32m\u2588\e[0m" 51 | } 52 | 53 | #依次打印小时,分钟,秒(个位和十位分别打印). 54 | while : 55 | do 56 | tput civis #隐藏光标. 57 | now_time 58 | print_time $hour_left 2 #需要打印的数字以及X轴坐标(第几列). 59 | print_time $hour_right 14 60 | print_punct 8 28 #定义(Y,X)坐标位8,28,打印时间分隔符号. 61 | print_punct 10 28 62 | print_time $min_left 30 63 | print_time $min_right 42 64 | print_punct 8 56 65 | print_punct 10 56 66 | print_time $sec_left 58 67 | print_time $sec_right 70 68 | echo 69 | sleep 1 70 | done 71 | 72 | -------------------------------------------------------------------------------- /chaper02/game.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | #功能描述(Description):石头剪刀布游戏. 3 | #计算机根据生成的随机数出拳,提示用户出拳, 4 | #将用户的输入与计算机的随机数进行比较,比较输赢. 5 | 6 | #1:石头,2:剪刀,3:布(随机数对3求模后,再加1的结果为1,2,3.) 7 | computer=$[RANDOM%3+1] 8 | clear 9 | echo "#########################" 10 | echo "# 石头剪刀布游戏. #" 11 | echo -e "#\033[32m 请您根据下列提示出拳: \033[0m#" 12 | echo "#########################" 13 | echo "|---------------|" 14 | echo "| 1.石头. |" 15 | echo "| 2.剪刀. |" 16 | echo "| 3.布. |" 17 | echo "|---------------|" 18 | read -p "请输入1-3的值:" person 19 | clear 20 | case $person in 21 | 1) 22 | if [[ "$computer" == 1 ]];then 23 | echo " __________________" 24 | echo "| 您出拳:石头. |" 25 | echo "|计算机出拳:石头. |" 26 | echo "|__________________|" 27 | echo -e "\033[32m平局.\033[0m" 28 | elif [[ "$computer" == 2 ]];then 29 | echo " __________________" 30 | echo "| 您出拳:石头. |" 31 | echo "|计算机出拳:剪刀. |" 32 | echo "|__________________|" 33 | echo -e "\033[32m恭喜,您赢了!\033[0m" 34 | elif [[ "$computer" == 3 ]];then 35 | echo " __________________" 36 | echo "| 您出拳:石头. |" 37 | echo "|计算机出拳:布. |" 38 | echo "|__________________|" 39 | echo -e "\033[32m计算机赢!\033[0m" 40 | fi;; 41 | 2) 42 | if [[ "$computer" == 1 ]];then 43 | echo " __________________" 44 | echo "| 您出拳:剪刀. |" 45 | echo "|计算机出拳:石头. |" 46 | echo "|__________________|" 47 | echo -e "\033[32m计算机赢!\033[0m" 48 | elif [[ "$computer" == 2 ]];then 49 | echo " __________________" 50 | echo "| 您出拳:剪刀. |" 51 | echo "|计算机出拳:剪刀. |" 52 | echo "|__________________|" 53 | echo -e "\033[32m平局.\033[0m" 54 | elif [[ "$computer" == 3 ]];then 55 | echo " __________________" 56 | echo "| 您出拳:剪刀. |" 57 | echo "|计算机出拳:布. |" 58 | echo "|__________________|" 59 | echo -e "\033[32m恭喜,您赢了!\033[0m" 60 | fi;; 61 | 3) 62 | if [[ "$computer" == 1 ]];then 63 | echo " __________________" 64 | echo "| 您出拳:布. |" 65 | echo "|计算机出拳:石头. |" 66 | echo "|__________________|" 67 | echo -e "\033[32m恭喜,您赢了!\033[0m" 68 | elif [[ "$computer" == 2 ]];then 69 | echo " __________________" 70 | echo "| 您出拳:布. |" 71 | echo "|计算机出拳:剪刀. |" 72 | echo "|__________________|" 73 | echo -e "\033[32m计算机赢!\033[0m" 74 | elif [[ "$computer" == 3 ]];then 75 | echo " __________________" 76 | echo "| 您出拳:布. |" 77 | echo "|计算机出拳:布. |" 78 | echo "|__________________|" 79 | echo -e "\033[32m平局.\033[0m" 80 | fi;; 81 | *) 82 | echo -e "\033[91m无效的输入值,请输入1-3范围内的值.\033[0m";; 83 | esac 84 | -------------------------------------------------------------------------------- /chaper06/dhcp.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | #功能描述(Description):一键安装部署DHCP服务. 3 | 4 | #定义变量:显示信息的颜色属性及配置文件路径. 5 | SUCCESS="echo -en \\033[1;32m" #绿色. 6 | FAILURE="echo -en \\033[1;31m" #红色. 7 | WARNING="echo -en \\033[1;33m" #黄色. 8 | NORMAL="echo -en \\033[0;39m" #黑色. 9 | conf_file=/etc/dhcp/dhcpd.conf 10 | 11 | #测试YUM源是否可用. 12 | test_yum(){ 13 | num=$(yum repolist | tail -1 | sed 's/.*: *//;s/,//') 14 | if [ $num -le 0 ];then 15 | $FAILURE 16 | echo "没有可用的Yum源." 17 | $NORMAL 18 | exit 19 | else 20 | if ! yum list dhcp &> /dev/null ;then 21 | $FAILURE 22 | echo "Yum源中没有dhcp软件包." 23 | $NORMAL 24 | exit 25 | fi 26 | fi 27 | } 28 | 29 | #安装部署dhcp软件包. 30 | install_dhcp(){ 31 | #如果软件包已经安装则提示警告信息并退出脚本. 32 | if rpm -q dhcp &> /dev/null ;then 33 | $WARNING 34 | echo "dhcp已安装." 35 | $NORMAL 36 | exit 37 | else 38 | yum -y install dhcp 39 | fi 40 | } 41 | 42 | 43 | #修改dhcp配置文件. 44 | modify_conf(){ 45 | #拷贝模板配置文件. 46 | /bin/cp -f /usr/share/doc/dhcp*/dhcpd.conf.example /etc/dhcp/dhcpd.conf 47 | sed -i '/10.152.187.0/{N;d}' $conf_file #删除多余配置,通过N读取多行,然后d删除. 48 | sed -i '/10.254.239.0/,+3d' $conf_file #删除多余配置,通过正则匹配某行以及之后的3行都删除. 49 | sed -i '/10.254.239.32/,+4d' $conf_file #删除多余配置,正则匹配某行以及后面的4行都删除. 50 | sed -i "s/10.5.5.0/$subnet/" $conf_file #设置DHCP网段. 51 | sed -i "s/255.255.255.224/$netmask/" $conf_file #设置DHCP网段的子网掩码. 52 | sed -i "s/10.5.5.26/$start/" $conf_file #设置DHCP为客户端分配的IP地址池起始IP. 53 | sed -i "s/10.5.5.30/$end/" $conf_file #设置DHCP为客户端分配的IP地址池结束IP. 54 | sed -i "s/ns1.internal.example.org/$dns/" $conf_file #设置为客户端分配的DNS. 55 | sed -i '/internal.example.org/d' $conf_file #删除多余的配置行. 56 | sed -i "/routers/s/10.5.5.1/$router/" $conf_file #设置为客户端分配的默认网关. 57 | sed -i '/broadcast-address/d' $conf_file #删除多余的配置行. 58 | } 59 | 60 | 61 | test_yum #调用函数,测试yum源. 62 | install_dhcp #调用函数,安装软件包. 63 | 64 | #读取必要的配置参数. 65 | echo -n "请输入DHCP网段(如:192.168.4.0):" 66 | $SUCCESS 67 | read subnet 68 | $NORMAL 69 | echo -n "请输入DHCP网段的子网掩码(如:255.255.255.0):" 70 | $SUCCESS 71 | read netmask 72 | $NORMAL 73 | echo -n "请输入为客户端分配的地址池(如:192.168.4.1-192.168.4.10):" 74 | $SUCCESS 75 | read pools 76 | $NORMAL 77 | echo -n "请输入为客户端分配的默认网关:" 78 | $SUCCESS 79 | read router 80 | $NORMAL 81 | echo -n "请输入为客户端分配的DNS服务器:" 82 | $SUCCESS 83 | read dns 84 | $NORMAL 85 | start=$(echo $pools | cut -d- -f1) #获取起始IP. 86 | end=$(echo $pools | cut -d- -f2) #获取结束IP. 87 | 88 | modify_conf #调用函数,修改配置文件. 89 | 90 | #重启服务. 91 | systemctl restart dhcpd &>/dev/null 92 | if [ $? -eq 0 ];then 93 | $SUCCESS 94 | echo "部署配置DHCP完毕." 95 | else 96 | $FAILURE 97 | echo "部署配置DHCP失败,通过 journalctl -xe查看日志." 98 | fi 99 | $NORMAL 100 | -------------------------------------------------------------------------------- /chaper02/sys_info.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | #本脚本获取系统各项参数指标,并根据预设阈值决定是否给管理员发送邮件报警 3 | 4 | #变量定义列表如下: 5 | #time:时间,loalip:eth0网卡IP,free_mem:剩余内存,free_disk:剩余磁盘 6 | #cpu_load:15分钟平均负载,login_user:登陆系统的用户,procs:当前进程数量 7 | local_time=$(date +"%Y%m%d %H:%M:%S") 8 | local_ip=$(ifconfig eth0 | grep netmask | tr -s " " | cut -d" " -f3) 9 | free_mem=$(cat /proc/meminfo |grep Avai |tr -s " " | cut -d" " -f2) 10 | free_disk=$(df | grep "/$" | tr -s " " | cut -d' ' -f4) 11 | cpu_load=$(cat /proc/loadavg | cut -d' ' -f3) 12 | login_user=$(who | wc -l) 13 | procs=$(ps aux | wc -l) 14 | 15 | #vmstat命令可以查看系统中CPU的中断数,上下文切换数量 16 | #CPU处于IO等待的时间,用户态及系统态消耗的CPU统计数据 17 | #vmstat命令输出的前2行是头部信息,第3行为开机到当前的平均数据, 18 | #第4行开始的数据是每秒实时数据,tail -n +4表示去掉前三行从第四行开始显示. 19 | 20 | #irq:中断,cs:上下文切换,usertime:用户态CPU,systime:系统态CPU,iowait:等待IO时间 21 | irq=$(vmstat 1 2 | tail -n +4 | tr -s ' ' | cut -d' ' -f12) 22 | cs=$(vmstat 1 2 | tail -n +4 | tr -s ' ' | cut -d' ' -f13) 23 | usertime=$(vmstat 1 2 | tail -n +4 | tr -s ' ' | cut -d' ' -f14) 24 | systime=$(vmstat 1 2 | tail -n +4 | tr -s ' ' | cut -d' ' -f15) 25 | iowait=$(vmstat 1 2| tail -n +4 | tr -s ' ' | cut -d' ' -f17) 26 | 27 | #当剩余内存不足1G时发送邮件给root报警 28 | [ $free_mem -lt 1048576 ] && \ 29 | echo "$local_time Free memory not enough. 30 | Free_mem:$free_mem on $local_ip" | \ 31 | mail -s Warning root@localhost 32 | #当剩余磁盘不足10G时发送邮件给root报警 33 | [ $free_disk -lt 10485760 ] && \ 34 | echo "$local_time Free disk not enough. 35 | root_free_disk:$free_disk on $local_ip" | \ 36 | mail -s Warning root@localhost 37 | #当CPU的15分钟平均负载超过4时发送邮件给root报警 38 | result=$(echo "$cpu_load > 4" | bc) 39 | [ $result -eq 1 ] && \ 40 | echo "$local_time CPU load to high 41 | CPU 15 averageload:$cpu_load on $local_ip" | \ 42 | mail -s Warning root@localhost 43 | #当系统实时在线人数超过3人时发送邮件给root报警 44 | [ $login_user -gt 3 ] && \ 45 | echo "$local_time Too many user. 46 | $login_user users login to $local_ip" | \ 47 | mail -s Warning root@localhost 48 | #当实时进程数量大于500时发送邮件给root报警 49 | [ $procs -gt 500 ] && \ 50 | echo "$local_time Too many procs. 51 | $procs proc are runing on $local_ip" | \ 52 | mail -s Warning root@localhost 53 | #当实时CPU中断数量大于5000时发送邮件给root报警 54 | [ $irq -gt 5000 ] && \ 55 | echo "$local_time Too many interupts. 56 | There are $irq interupts on $local_ip" | \ 57 | mail -s Warning root@localhost 58 | #当实时CPU上下文切换数量大于5000时发送邮件给root报警 59 | [ $cs -gt 5000 ] && \ 60 | echo "$local_time Too many Content Switches. 61 | $cs of context switches per second on $local_ip" | \ 62 | mail -s Warning root@localhost 63 | #当用户态进程占用CPU超70%时发送邮件给root报警 64 | [ $usertime -gt 70 ] && \ 65 | echo "$local_time CPU load to high. 66 | Time spend running non-kernel code:$usertime on $local_ip" | \ 67 | mail -s Warning root@localhost 68 | #当内核态进程占用CPU超70%时发送邮件给root报警 69 | [ $systime -gt 70 ] && \ 70 | echo "$local_time CPU load to high. 71 | Time spend running non-kernel code:$systime on $local_ip" | \ 72 | mail -s Warning root@localhost 73 | #当CPU消耗大量时间等待磁盘IO时发送邮件给root报警 74 | [ $iowait -gt 40 ] && \ 75 | echo "$local_time Disk to slow. 76 | CPU spend too many time wait disk I/O:$iowait on $local_ip" | \ 77 | mail -s Warning root@localhost 78 | -------------------------------------------------------------------------------- /chaper06/clone-vm.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | #功能描述(Description):快速克隆虚拟机脚本. 3 | #使用qemu-img工具基于虚拟机后端模板磁盘创建前端盘, 4 | #使用cp拷贝XML描述文件,通过sed工具修改XML文件. 5 | 6 | #定义错误返回码(exit code): 7 | # 65 -> can't found base vm image. 8 | # 66 -> can't found base vm. 9 | # 67 -> vm disk image already exist. 10 | # 68 -> vm's XML file already exist. 11 | # 69 -> vm name already exist. 12 | 13 | #定义变量:镜像存储路径,后端模板虚拟机名称,已存在虚拟机列表. 14 | IMG_DIR="/var/lib/libvirt/images" 15 | XML_DIR="/etc/libvirt/qemu" 16 | BASE_VM="centos7.5_6" 17 | exist_vm=$(virsh list --name --all) 18 | 19 | #定义变量:显示信息的颜色属性. 20 | SUCCESS="echo -en \\033[1;32m" #绿色. 21 | FAILURE="echo -en \\033[1;31m" #红色. 22 | WARNING="echo -en \\033[1;33m" #黄色. 23 | NORMAL="echo -en \\033[0;39m" #黑色. 24 | 25 | 26 | #测试后端模板虚拟机镜像文件是否存在. 27 | if [[ ! -e ${IMG_DIR}/${BASE_VM}.qcow2 ]];then 28 | $FAILURE 29 | echo "找不到后端模板虚拟机镜像文件$IMG_DIR/${BASE_VM}.qcow2." 30 | $NORMAL 31 | exit 65 32 | fi 33 | 34 | #测试后端模板虚拟机XML文件是否存在. 35 | if [[ ! -e ${XML_DIR}/centos7.5_6.xml ]];then 36 | $FAILURE 37 | echo "后端模板虚拟机${BASE_VM}.xml文件不存在." 38 | $NORMAL 39 | exit 66 40 | fi 41 | 42 | read -p "请输入新克隆的虚拟机名称:" newvm 43 | 44 | #测试虚拟机镜像文件是否已经存在. 45 | if [[ -e $IMG_DIR/$newvm.qcow2 ]];then 46 | $FAILURE 47 | echo "${IMG_DIR}/${newvm}.qcow2虚拟机镜像文件已存在." 48 | $NORMAL 49 | exit 67 50 | fi 51 | 52 | #测试虚拟机的XML文件是否已经存在. 53 | if [[ -e ${XML_DIR}/${newvm}.xml ]];then 54 | $FAILURE 55 | echo "虚拟机${newvm}.xml文件已存在." 56 | $NORMAL 57 | exit 68 58 | fi 59 | 60 | #测试虚拟机名称是否已经存在. 61 | for i in $exist_vm 62 | do 63 | if [[ "$newvm" == "$i" ]];then 64 | $FAILURE 65 | echo "名称为${newvm}的虚拟机已经存在." 66 | $NORMAL 67 | exit 69 68 | fi 69 | done 70 | 71 | #使用qemu-img克隆虚拟机镜像文件. 72 | echo -en "Creating a new virtual machine disk image...\t" 73 | qemu-img create -f qcow2 -b ${IMG_DIR}/${BASE_VM}.qcow2 ${IMG_DIR}/${newvm}.qcow2 &>/dev/null 74 | $SUCCESS 75 | echo "[OK]" 76 | $NORMAL 77 | 78 | #克隆XML文件. 79 | virsh dumpxml $BASE_VM > ${XML_DIR}/${newvm}.xml 80 | #生成随机UUID. 81 | UUID=$(uuidgen) 82 | #修改XML文件中的UUID. 83 | sed -i "//c $UUID" ${XML_DIR}/${newvm}.xml 84 | #修改XML文件中的虚拟机名称. 85 | sed -i "//c $newvm" ${XML_DIR}/${newvm}.xml 86 | #修改XML文件中虚拟机对应的磁盘镜像文件. 87 | sed -i "s#${IMG_DIR}/${BASE_VM}\.qcow2#${IMG_DIR}/${newvm}.qcow2#" ${XML_DIR}/${newvm}.xml 88 | #获取XML文件中的MAC地址列表. 89 | mac=$(sed -rn "s//\1/p" ${XML_DIR}/${newvm}.xml) 90 | #使用循环将所有MAC地址修改为新的随机MAC地址. 91 | pools="0123456789abcdef" 92 | for i in $mac 93 | do 94 | new_mac="52:54:00" 95 | for j in {1..3} 96 | do 97 | tmp1=${pools:$[RANDOM%16]:1} 98 | tmp2=${pools:$[RANDOM%16]:1} 99 | new_mac=${new_mac}:${tmp1}${tmp2} 100 | done 101 | sed -i "s/$i/'$new_mac'/" ${XML_DIR}/${newvm}.xml 102 | done 103 | 104 | #使用新的XML文件定义虚拟机. 105 | echo -en "Defining a new virtual machine...\t\t" 106 | virsh define ${XML_DIR}/${newvm}.xml &>/dev/null 107 | if [ $? -eq 0 ];then 108 | $SUCCESS 109 | echo "[OK]" 110 | $NORMAL 111 | fi 112 | -------------------------------------------------------------------------------- /chaper07/monitor.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | #功能描述(Description):监控服务器主要性能参数指标. 3 | #监控项目:内核信息,主机名称,IP地址,登陆账户,内存与swap信息,磁盘信息,CPU负载. 4 | 5 | kernel=$(uname -r) #内核信息 6 | release=$(cat /etc/redhat-release) #操作系统版本 7 | hostname=$HOSTNAME #主机名称 8 | localip=$(ip a s | awk '/inet /{print $2}') #本地IP地址列表 9 | mem_total=$(free | awk '/Mem/{print $2}') #总内存容量 10 | mem_free=$(free | awk '/Mem/{print $NF}') #剩余内存容量 11 | swap_total=$(free | awk '/Swap/{print $2}') #总swap容量 12 | swap_free=$(free | awk '/Swap/{print $NF}') #剩余swap容量 13 | disk=$(df | awk '/^\/dev/{print $1,$2,$4}'|column -t) #磁盘信息 14 | load1=$(uptime | sed 's/,//g' | awk '{print $(NF-2)}') #CPU最近1分钟平均负载 15 | load5=$(uptime | sed 's/,//g' | awk '{print $(NF-1)}') #CPU最近5分钟平均负载 16 | load15=$(uptime | sed 's/,//g' | awk '{print $NF}') #CPU最近15分钟平均负载 17 | login_users=$(who | wc -l) #登陆用户数量 18 | procs=$(ps aux | wc -l) #进程数量 19 | users=$(sed -n '$=' /etc/passwd) #系统总账户数量 20 | cpu_info=$(LANG=C lscpu | awk -F: '/Model name/ {print $2}') #CPU型号 21 | cpu_core=$(awk '/processor/{core++} END{print core}' /proc/cpuinfo) #CPU内核数量 22 | 23 | yum -y -q install sysstat &>/dev/null #安装性能监控软件 24 | echo -e "\033[34m提取磁盘性能指标,请稍后...\033[0m" 25 | tps=$(LANG=C sar -d -p 1 6 | awk '/Average/' | tail -n +2 | awk '{print "["$2"]磁盘平均IO数量:"$3}') & 26 | read_write=$(LANG=C sar -d -p 1 6 | awk '/Average/' | tail -n +2 | awk '{print "["$2"]平均每秒读写扇区量:"$4,$5}') & 27 | 28 | irq=$(vmstat 1 2 | tail -n +4 | awk '{print $11}') #中断数量 29 | cs=$(vmstat 1 2 | tail -n +4 | awk '{print $12}') #上下文切换数量 30 | 31 | top_proc_mem=$(ps --no-headers -eo comm,rss | sort -k2 -n | tail -10) #占用内存资源最多的10个进程列表 32 | top_proc_cpu=$(ps --no-headers -eo comm,pcpu | sort -k2 -n | tail -5) #占用CPU资源最多的5个进程列表 33 | 34 | #获取网卡流量,接收|发送的数据流量,单位为字节bytes). 35 | net_monitor=$(cat /proc/net/dev | tail -n +3 | \ 36 | awk 'BEGIN{ print "网卡名称 入站数据流量(bytes) 出站数据流量(bytes)" } \ 37 | { print $1,$2,$10 }' | column -t) 38 | 39 | #输出数据信息. 40 | echo -e "\033[32m--------------本机主要数据参数表-----------------\033[0m" 41 | echo -e "本机IP地址列表:\033[32m$localip\033[0m" 42 | echo -e "本机主机名称:\033[32m$hostname\033[0m" 43 | echo -e "操作系统版本:\033[32m$release\033[0m,内核版本:\033[32m$kernel\033[0m" 44 | echo -e "CPU型号为:\033[32m$cpu_info\033[0m,CPU内核数量:\033[32m$cpu_core\033[0m" 45 | echo -e "本机总内存容量:\033[32m$mem_total\033[0m,剩余可用内存容量:\033[32m$mem_free\033[0m" 46 | echo -e "本机swap总容量:\033[32m$swap_total\033[0m,剩余容量:\033[32m$swap_free\033[0m" 47 | echo -e "CPU最近1分钟,5分钟,15分钟的平均负载分别为:\033[32m$load1 $load5 $load15\033[0m" 48 | echo -e "本机总账户数量为:\033[32m$users\033[0m,当前登陆系统的账户数量:\033[32m$login_users\033[0m" 49 | echo -e "当前系统中启动的进程数量:\033[32m$procs\033[0m" 50 | echo -e "占用CPU资源最多的5个进程列表为:" 51 | echo -e "\033[32m$top_proc_cpu\033[0m" 52 | echo -e "占用内存资源最多的10个进程列表为:" 53 | echo -e "\033[32m$top_proc_mem\033[0m" 54 | echo -e "CPU中断数量:\033[32m$irq\033[0m,CPU上下文切换数量:\033[32m$cs\033[0m" 55 | echo -e "每个磁盘分区的总容量与剩余容量信息如下:" 56 | echo -e "$disk" 57 | echo -e "$tps" 58 | echo -e "$read_write" 59 | echo -e "$net_monitor" 60 | echo -e "\033[32m------------------The End------------------------\033[0m" 61 | -------------------------------------------------------------------------------- /chaper07/mysql_monitor.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | #定义数据库相关变量. 4 | MYSQL_USER=root 5 | MYSQL_PASS=123456 6 | MYSQL_PORT=3306 7 | MYSQL_HOST=localhost 8 | MYSQL_ADMIN="mysqladmin -u$MYSQL_USER -p$MYSQL_PASS -P$MYSQL_PORT -h$MYSQL_HOST" 9 | MYSQL_COMM="mysql -u$MYSQL_USER -p$MYSQL_PASS -P$MYSQL_PORT -h$MYSQL_HOST -e" 10 | 11 | #定义变量:显示信息的颜色属性. 12 | SUCCESS="echo -en \\033[1;32m" #绿色. 13 | FAILURE="echo -en \\033[1;31m" #红色. 14 | WARNING="echo -en \\033[1;33m" #黄色. 15 | NORMAL="echo -en \\033[0;39m" #黑色. 16 | 17 | #检查数据库服务器状态. 18 | $MYSQL_ADMIN ping &> /dev/null 19 | if [ $? -ne 0 ];then 20 | $FAILURE 21 | echo "无法连接数据库服务器" 22 | $NORMAL 23 | exit 24 | else 25 | echo -n "数据库状态: " 26 | $SUCCESS 27 | echo "[OK]" 28 | $NORMAL 29 | fi 30 | 31 | #过滤数据库启动时间. 32 | RUN_TIME=$($MYSQL_COMM "SHOW GLOBAL STATUS LIKE 'uptime'" | awk '/Uptime/{print $2}') 33 | echo -n "数据库已运行时间(秒): " 34 | $SUCCESS 35 | echo $RUN_TIME 36 | $NORMAL 37 | 38 | #过滤数据库列表. 39 | DB_LIST=$($MYSQL_COMM "SHOW DATABASES") 40 | DB_COUNT=$($MYSQL_COMM "SHOW DATABASES" | awk 'NR>=2&&/^[^+]/{db_count++} END{print db_count}') 41 | echo -n "该数据库有$DB_COUNT个数据库,分别为:" 42 | $SUCCESS 43 | echo $DB_LIST 44 | $NORMAL 45 | 46 | #查询MySQL最大并发连接数. 47 | MAX_CON=$($MYSQL_COMM "SHOW VARIABLES LIKE 'max_connections'" | awk '/max/{print $2}') 48 | echo -n "MySQL最大并发连接数: " 49 | $SUCCESS 50 | echo $MAX_CON 51 | $NORMAL 52 | 53 | #查看SELECT指令被执行的次数. 54 | NUM_SELECT=$($MYSQL_COMM "SHOW GLOBAL STATUS LIKE 'com_select'" | awk '/Com_select/{print $2}') 55 | echo -n "SELECT被执行的次数: " 56 | $SUCCESS 57 | echo $NUM_SELECT 58 | $NORMAL 59 | 60 | #查看UPDATE指令被执行的次数. 61 | NUM_UPDATE=$($MYSQL_COMM "SHOW GLOBAL STATUS LIKE 'com_update'" | awk '/Com_update/{print $2}') 62 | echo -n "UPDATE被执行的次数: " 63 | $SUCCESS 64 | echo $NUM_UPDATE 65 | $NORMAL 66 | 67 | #查看DELETE指令被执行的次数. 68 | NUM_DELETE=$($MYSQL_COMM "SHOW GLOBAL STATUS LIKE 'com_delete'" | awk '/Com_delete/{print $2}') 69 | echo -n "DELETE被执行的次数: " 70 | $SUCCESS 71 | echo $NUM_DELETE 72 | $NORMAL 73 | 74 | #查看INSERT指令被执行的次数. 75 | NUM_INSERT=$($MYSQL_COMM "SHOW GLOBAL STATUS LIKE 'com_insert'" | awk '/Com_insert/{print $2}') 76 | echo -n "INSERT被执行的次数: " 77 | $SUCCESS 78 | echo $NUM_INSERT 79 | $NORMAL 80 | 81 | #查看COMMIT指令被执行的次数. 82 | NUM_COMMIT=$($MYSQL_COMM "SHOW GLOBAL STATUS LIKE 'com_commit'" | awk '/Com_commit/{print $2}') 83 | echo -n "COMMIT被执行的次数: " 84 | $SUCCESS 85 | echo $NUM_COMMIT 86 | $NORMAL 87 | 88 | #查看ROLLBACK指令被执行的次数. 89 | NUM_ROLLBACK=$($MYSQL_COMM "SHOW GLOBAL STATUS LIKE 'com_rollback'" | awk '/Com_rollback/{print $2}') 90 | echo -n "ROLLBACK被执行的次数: " 91 | $SUCCESS 92 | echo $NUM_ROLLBACK 93 | $NORMAL 94 | 95 | #查看ROLLBACK指令被执行的次数. 96 | NUM_ROLLBACK=$($MYSQL_COMM "SHOW GLOBAL STATUS LIKE 'com_rollback'" | awk '/Com_rollback/{print $2}') 97 | echo -n "ROLLBACK被执行的次数: " 98 | $SUCCESS 99 | echo $NUM_ROLLBACK 100 | $NORMAL 101 | 102 | #查看服务器执行的指令数量. 103 | NUM_QUESTION=$($MYSQL_COMM "SHOW GLOBAL STATUS LIKE 'Questions'" | awk '/Questions/{print $2}') 104 | echo -n "Questions服务器执行的指令数量: " 105 | $SUCCESS 106 | echo $NUM_QUESTION 107 | $NORMAL 108 | 109 | NUM_SLOW_QUERY=$($MYSQL_COMM "SHOW GLOBAL STATUS LIKE 'slow_queries'" | awk '/Slow_queries/{print $2}') 110 | echo -n "SLOW Query慢查询数量: " 111 | $SUCCESS 112 | echo $NUM_SLOW_QUERY 113 | $NORMAL 114 | 115 | echo -n "数据库QPS: " 116 | $SUCCESS 117 | awk 'BEGIN{print '"$NUM_QUESTION/$RUN_TIME"'}' 118 | $NORMAL 119 | 120 | echo -n "数据库TPS: " 121 | $SUCCESS 122 | awk 'BEGIN{print '"($NUM_COMMIT+$NUM_ROLLBACK)/$RUN_TIME"'}' 123 | $NORMAL 124 | -------------------------------------------------------------------------------- /chaper07/netstat.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | #功能描述(Description):监控网络连接状态脚本. 3 | 4 | #所有TCP连接的个数. 5 | TCP_Total=$(ss -s | awk '$1=="TCP"{print $2}') 6 | #所有UDP连接的个数. 7 | UDP_Total=$(ss -s | awk '$1=="UDP"{print $2}') 8 | #所有Unix sockets连接个数. 9 | Unix_sockets_Total=$(ss -ax | awk 'BEGIN{count=0} {count++} END{print count}') 10 | #所有处于Listen监听状态的TCP端口个数. 11 | TCP_Listen_Total=$(ss -antlpH | awk 'BEGIN{count=0} {count++} END{print count}') 12 | #所有处于ESTABLISHED状态的TCP连接个数. 13 | TCP_Estab_Total=$(ss -antpH | awk 'BEGIN{count=0} /^ESTAB/{count++} END{print count}') 14 | #所有处于SYN-RECV状态的TCP连接个数. 15 | TCP_SYN_RECV_Total=$(ss -antpH | awk 'BEGIN{count=0} /^SYN-RECV/{count++} END{print count}') 16 | #所有处于TIME-WAIT状态的TCP连接个数. 17 | TCP_TIME_WAIT_Total=$(ss -antpH | awk 'BEGIN{count=0} /^TIME-WAIT/{count++} END{print count}') 18 | #所有处于TIME-WAIT1状态的TCP连接个数. 19 | TCP_TIME_WAIT1_Total=$(ss -antpH | awk 'BEGIN{count=0} /^TIME-WAIT1/{count++} END{print count}') 20 | #所有处于TIME-WAIT2状态的TCP连接个数. 21 | TCP_TIME_WAIT2_Total=$(ss -antpH | awk 'BEGIN{count=0} /^TIME-WAIT2/{count++} END{print count}') 22 | #所有远程主机的TCP连接次数. 23 | TCP_Remote_Count=$(ss -antH | awk '$1!~/LISTEN/{IP[$5]++} END{ for(i in IP){print IP[i],i} }' | sort -nr) 24 | #每个端口被访问的次数. 25 | TCP_Port_Count=$(ss -antH | sed -r 's/ +/ /g' | awk -F"[ :]" '$1!~/LISTEN/{port[$5]++} END{for(i in port){print port[i],i}}' | sort -nr) 26 | 27 | #定义输出颜色. 28 | SUCCESS="echo -en \\033[1;32m" #绿色. 29 | NORMAL="echo -en \\033[0;39m" #黑色. 30 | 31 | #显示TCP连接总数. 32 | tcp_total(){ 33 | echo -n "TCP连接总数: " 34 | $SUCCESS 35 | echo "$TCP_Total" 36 | $NORMAL 37 | } 38 | 39 | #显示处于LISTEN状态的TCP端口个数. 40 | tcp_listen(){ 41 | echo -n "处于LISTEN状态的TCP端口个数: " 42 | $SUCCESS 43 | echo "$TCP_Listen_Total" 44 | $NORMAL 45 | } 46 | 47 | #显示处于ESTABLISHED状态的TCP连接个数. 48 | tcp_estab(){ 49 | echo -n "处于ESTAB状态的TCP连接个数: " 50 | $SUCCESS 51 | echo "$TCP_Estab_Total" 52 | $NORMAL 53 | } 54 | 55 | #显示处于SYN-RECV状态的TCP连接个数. 56 | tcp_syn_recv(){ 57 | echo -n "处于SYN-RECV状态的TCP连接个数: " 58 | $SUCCESS 59 | echo "$TCP_SYN_RECV_Total" 60 | $NORMAL 61 | } 62 | 63 | #显示处于TIME-WAIT状态的TCP连接个数. 64 | tcp_time_wait(){ 65 | echo -n "处于TIME-WAIT状态的TCP连接个数: " 66 | $SUCCESS 67 | echo "$TCP_TIME_WAIT_Total" 68 | $NORMAL 69 | } 70 | 71 | #显示处于TIME-WAIT1状态的TCP连接个数. 72 | tcp_time_wait1(){ 73 | echo -n "处于TIME-WAIT1状态的TCP连接个数: " 74 | $SUCCESS 75 | echo "$TCP_TIME_WAIT1_Total" 76 | $NORMAL 77 | } 78 | 79 | #显示处于TIME-WAIT2状态的TCP连接个数. 80 | tcp_time_wait2(){ 81 | echo -n "处于TIME-WAIT2状态的TCP连接个数: " 82 | $SUCCESS 83 | echo "$TCP_TIME_WAIT2_Total" 84 | $NORMAL 85 | } 86 | 87 | #显示UDP连接总数. 88 | udp_total(){ 89 | echo -n "UDP连接总数: " 90 | $SUCCESS 91 | echo "$UDP_Total" 92 | $NORMAL 93 | } 94 | 95 | #显示Unix sockets连接总数. 96 | unix_total(){ 97 | echo -n "Unix sockets连接总数: " 98 | $SUCCESS 99 | echo "$Unix_sockets_Total" 100 | $NORMAL 101 | } 102 | 103 | #显示每个远程主机的访问次数. 104 | remote_count(){ 105 | echo "每个远程主机与本机的并发连接数: " 106 | $SUCCESS 107 | echo "$TCP_Remote_Count" 108 | $NORMAL 109 | } 110 | 111 | #显示每个端口的并发连接数. 112 | port_count(){ 113 | echo "每个端口的并发连接数: " 114 | $SUCCESS 115 | echo "$TCP_Port_Count" 116 | $NORMAL 117 | } 118 | 119 | print_info(){ 120 | echo -e "------------------------------------------------------" 121 | $1 122 | } 123 | 124 | print_info tcp_total 125 | print_info tcp_listen 126 | print_info tcp_estab 127 | print_info tcp_syn_recv 128 | print_info tcp_time_wait 129 | print_info tcp_time_wait1 130 | print_info tcp_time_wait2 131 | print_info udp_total 132 | print_info unix_total 133 | print_info remote_count 134 | print_info port_count 135 | echo -e "------------------------------------------------------" 136 | -------------------------------------------------------------------------------- /chaper05/mouse.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | #功能描述(Description):抓住随机出现的老鼠算你赢. 3 | 4 | #使用Ctrl+C中断脚本时显示光标. 5 | trap 'proc_exit' EXIT INT 6 | 7 | #获取屏幕最大行和列数,定义游戏地图的大小为屏幕的1/4. 8 | lines=`tput lines` 9 | column=`tput cols` 10 | left=2 11 | right=$[column/2] 12 | top=2 13 | bottom=$[lines/2] 14 | 15 | #定义函数,绘制一个长方形的游戏地图区域,使用#符号绘制游戏地图边界. 16 | draw_map(){ 17 | save_property=$(stty -g) #保存当前终端所有属性. 18 | tput clear 19 | tput civis #关闭光标显示. 20 | echo -e "\033[1m\n\t按w(上),s(下),a(左),d(右),q(退出)键,控制笑脸抓住随机出现的小老鼠." 21 | for y in `seq $top $bottom` #对地图的Y坐标(行号)循环. 22 | do 23 | local x=$left 24 | if [[ $y -eq $top || $y -eq $bottom ]];then #判断Y坐标是否为顶部行或者底部行. 25 | while [ $x -le $right ] 26 | do 27 | tput cup $y $x 28 | echo -ne "\033[37;42m#\033[0m" #Y坐标在left到right之间全部绘制#符号. 29 | let x++ 30 | done 31 | else 32 | for m in $left $right #在Y坐标为left和right位置绘制两个#符号. 33 | do 34 | tput cup $y $m 35 | echo -ne "\033[37;42m#\033[0m" 36 | done 37 | fi 38 | done 39 | echo 40 | } 41 | 42 | #定义函数,对游戏地图区域内填充空格,以完成对地图的清屏操作,地图边界的#符号不清除. 43 | clear_screen(){ 44 | for((i=3;i<=$[bottom-1];i++)) 45 | do 46 | space="" 47 | for((j=3;j<=$[right-1];j++)) 48 | do 49 | space=${space}" " #定义变量,值为right-3个空格. 50 | done 51 | tput cup $i 3 #使用空格覆盖清理游戏地图. 52 | echo -n "$space" 53 | done 54 | } 55 | 56 | #定义函数,在地图内部的指定坐标绘制一只小老鼠,Unicode编码中1F42D是老鼠形状. 57 | draw_mouse(){ 58 | tput cup $1 $2 59 | echo -en "\U1f42d" 60 | } 61 | 62 | #定义函数,在地图内部的指定坐标绘制一个笑脸,Unicode编码中1F642是笑脸形状. 63 | draw_player(){ 64 | tput cup $1 $2 65 | echo -en "\U1f642" 66 | } 67 | 68 | #定义函数,退出脚本时还原终端属性. 69 | proc_exit(){ 70 | tput cnorm 71 | stty $save_property 72 | echo "GameOver." 73 | exit 74 | } 75 | 76 | #定义主函数,循环在屏幕显示笑脸和小老鼠,通过read读取用户输入,控制笑脸的移动. 77 | get_key(){ 78 | man_x=4 #笑脸的初始坐标X,Y=4,4 79 | man_y=4 80 | while : 81 | do 82 | tmp_col=$[right-2] 83 | tmp_line=$[bottom-1] 84 | rand_x=$[RANDOM%(tmp_col-left)+left+1] #定义老鼠的随机坐标X. 85 | rand_y=$[RANDOM%(tmp_line-top)+top+1] #定义老鼠的随机坐标Y. 86 | draw_player $man_y $man_x 87 | draw_mouse $rand_y $rand_x 88 | #当笑脸和小老鼠坐标相同时,脚本退出. 89 | if [[ $man_x -eq $rand_x && $man_y -eq $rand_y ]];then 90 | proc_exit 91 | fi 92 | stty -echo #关闭输入的回显功能. 93 | #读取用户的输入,控制笑脸的新坐标. 94 | #如果笑脸坐标到达游戏地图的边缘则游戏结束. 95 | read -s -n 1 input 96 | if [[ $input == "q" || $input == "Q" ]];then 97 | proc_exit 98 | elif [[ $input == "w" || $input == "W" ]];then 99 | let man_y-- 100 | [[ $man_y -le $top || $man_y -ge $bottom ]] && proc_exit 101 | draw_player $man_y $man_x 102 | elif [[ $input == "s" || $input == "S" ]];then 103 | let man_y++ 104 | [[ $man_y -le $top || $man_y -ge $bottom ]] && proc_exit 105 | draw_player $man_y $man_x 106 | elif [[ $input == "a" || $input == "A" ]];then 107 | let man_x-- 108 | [[ $man_x -le $left || $man_x -ge $right ]] && proc_exit 109 | draw_player $man_y $man_x 110 | elif [[ $input == "d" || $input == "D" ]];then 111 | let man_x++ 112 | [[ $man_x -le $left || $man_x -ge $right ]] && proc_exit 113 | draw_player $man_y $man_x 114 | fi 115 | clear_screen 116 | done 117 | } 118 | 119 | draw_map 120 | get_key 121 | -------------------------------------------------------------------------------- /chaper06/vsftpd.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | #功能描述(Description):自动部署配置vsftpd服务器,管理FTP服务器,针对RHEL|CentOS系统. 3 | #本地账户访问FTP的共享目录为/common,其中/common/pub为可上传目录. 4 | #匿名账户访问FTP的共享目录为/var/ftp,其中/var/ftp/pub为可上传目录. 5 | 6 | #定义变量:显示信息的颜色属性及配置文件路径. 7 | SUCCESS="echo -en \\033[1;32m" #绿色. 8 | FAILURE="echo -en \\033[1;31m" #红色. 9 | WARNING="echo -en \\033[1;33m" #黄色. 10 | NORMAL="echo -en \\033[0;39m" #黑色. 11 | conf_file=/etc/vsftpd/vsftpd.conf 12 | 13 | #####从这里开始先将所有需要的功能定义为函数.##### 14 | #定义脚本的主菜单功能. 15 | menu(){ 16 | clear 17 | echo "-----------------------------------" 18 | echo "# 菜单(Menu) #" 19 | echo "-----------------------------------" 20 | echo "# 1.安装配置vsftpd. #" 21 | echo "# 2.创建FTP账户. #" 22 | echo "# 3.删除FTP账户. #" 23 | echo "# 4.配置匿名账户. #" 24 | echo "# 5.启动关闭vsftpd. #" 25 | echo "# 6.退出脚本. #" 26 | echo "-----------------------------------" 27 | echo 28 | } 29 | 30 | #定义配置匿名账户的子菜单. 31 | anon_sub_menu(){ 32 | clear 33 | echo "-----------------------------------" 34 | echo "# 匿名配置子菜单(Menu) #" 35 | echo "-----------------------------------" 36 | echo "# 1.禁用匿名账户. #" 37 | echo "# 2.启用匿名登陆. #" 38 | echo "# 3.允许匿名账户上传. #" 39 | echo "-----------------------------------" 40 | echo 41 | } 42 | 43 | #定义服务管理的子菜单. 44 | service_sub_menu(){ 45 | clear 46 | echo "-----------------------------------" 47 | echo "# 服务管理子菜单(Menu) #" 48 | echo "-----------------------------------" 49 | echo "# 1.启动vsftpd. #" 50 | echo "# 2.关闭vsftpd. #" 51 | echo "# 3.重启vsftpd. #" 52 | echo "-----------------------------------" 53 | echo 54 | } 55 | 56 | #测试YUM是否可用. 57 | test_yum(){ 58 | num=$(yum repolist | tail -1 | sed 's/.*: *//;s/,//') 59 | if [ $num -le 0 ];then 60 | $FAILURE 61 | echo "没有可用的Yum源." 62 | $NORMAL 63 | exit 64 | else 65 | if ! yum list vsftpd &> /dev/null ;then 66 | $FAILURE 67 | echo "Yum源中没有vsftpd软件包." 68 | $NORMAL 69 | exit 70 | fi 71 | fi 72 | } 73 | 74 | #安装部署vsftpd软件包. 75 | install_vsftpd(){ 76 | #如果软件包已经安装则提示警告信息并退出脚本. 77 | if rpm -q vsftpd &> /dev/null ;then 78 | $WARNING 79 | echo "vsftpd已安装." 80 | $NORMAL 81 | exit 82 | else 83 | yum -y install vsftpd 84 | fi 85 | } 86 | 87 | #修改初始化配置文件. 88 | init_config(){ 89 | #备份配置文件. 90 | [ ! -e $conf_file.bak ] && cp $conf_file{,.bak} 91 | 92 | #为本地账户创建共享目录/common,修改配置文件指定共享根目录. 93 | [ ! -d /common/pub ] && mkdir -p /common/pub 94 | chmod a+w /common/pub 95 | grep -q local_root $conf_file || sed -i '$a local_root=/common' $conf_file 96 | 97 | #默认客户端通过本地账户访问FTP时 98 | #允许使用cd命令跳出共享目录,可以看到/etc等系统目录及文件. 99 | #通过设置chroot_local_user=YES可以将账户禁锢在自己的家目录,无法进入其他目录. 100 | sed -i 's/^#chroot_local_user=YES/chroot_local_user=YES/' $conf_file 101 | } 102 | 103 | #创建FTP账户,如果账户已存在则直接退出脚本. 104 | create_ftpuser(){ 105 | if id $1 &> /dev/null ;then 106 | $FAILURE 107 | echo "$1账户已存在." 108 | $NORMAL 109 | exit 110 | else 111 | useradd $1 112 | echo "$2" | passwd --stdin $1 &>/dev/null 113 | fi 114 | } 115 | 116 | #删除FTP账户,如果账户不存在则直接退出脚本. 117 | delete_ftpuser(){ 118 | if ! id $1 &> /dev/null ;then 119 | $FAILURE 120 | echo "$1账户不存在." 121 | $NORMAL 122 | exit 123 | else 124 | userdel $1 125 | fi 126 | } 127 | 128 | #配置匿名账户. 129 | #第一个位置参数为1则将匿名账户禁用. 130 | #第一个位置参数为2则开启匿名账户登陆功能. 131 | #第一个位置参数为3则设置允许匿名账户上传文件. 132 | anon_config(){ 133 | if [ ! -f $conf_file ];then 134 | $FAILURE 135 | echo "配置文件不存在." 136 | $NORMAL 137 | exit 138 | fi 139 | #设置anonymous_enable=YES可以开启匿名登陆功能,默认为开启状态. 140 | #设置anonymous_enable=NO可以禁止匿名登陆功能. 141 | #设置anon_upload_enable=YES可以允许匿名上传文件,默认该配置被注释. 142 | #设置anon_mkdir_write_enable=YES可以允许匿名账户创建目录,默认该配置被注释. 143 | case $1 in 144 | 1) 145 | sed -i 's/anonymous_enable=YES/anonymous_enable=NO/' $conf_file 146 | systemctl restart vsftpd;; 147 | 2) 148 | sed -i 's/anonymous_enable=NO/anonymous_enable=YES/' $conf_file 149 | systemctl restart vsftpd;; 150 | 3) 151 | sed -i 's/^#anon_/anon_/' $conf_file 152 | chmod a+w /var/ftp/pub 153 | systemctl restart vsftpd;; 154 | esac 155 | } 156 | 157 | #服务管理. 158 | #第一个位置参数为start时启动vsftpd服务. 159 | #第一个位置参数为stop时关闭vsftpd服务. 160 | #第一个位置参数为restart时重启vsftpd服务. 161 | proc_manager(){ 162 | if ! rpm -q vsftpd &>/dev/null ;then 163 | $FAILURE 164 | echo "未安装vsftpd软件包." 165 | $NORMAL 166 | exit 167 | fi 168 | case $1 in 169 | start) 170 | systemctl start vsftpd;; 171 | stop) 172 | systemctl stop vsftpd;; 173 | restart) 174 | systemctl restart vsftpd;; 175 | esac 176 | } 177 | 178 | 179 | ######从这里开始调用前面定义的函数.##### 180 | menu 181 | read -p "请输入选项[1-6]:" input 182 | case $input in 183 | 1) 184 | test_yum #测试yum源. 185 | install_vsftpd #安装vsftpd软件包. 186 | init_config;; #初始化修改配置文件. 187 | 2) 188 | read -p "请输入账户名称:" username 189 | read -s -p "请输入账户密码:" password 190 | echo 191 | create_ftpuser $username $password;; #创建FTP账户. 192 | 3) 193 | read -p "请输入账户名称:" username 194 | delete_ftpuser $username $password;; #删除FTP账户. 195 | 4) 196 | anon_sub_menu 197 | read -p "请输入选项[1-3]:" anon 198 | if [ $anon -eq 1 ];then 199 | anon_config 1 #禁止匿名登陆. 200 | elif [ $anon -eq 2 ];then 201 | anon_config 2 #启用匿名登陆. 202 | elif [ $anon -eq 3 ];then 203 | anon_config 3 #允许匿名上传. 204 | fi;; 205 | 5) 206 | service_sub_menu 207 | read -p "请输入选项[1-3]:" proc 208 | if [ $proc -eq 1 ];then 209 | proc_manager start #启动vsftpd服务. 210 | elif [ $proc -eq 2 ];then 211 | proc_manager stop #关闭vsftpd服务. 212 | elif [ $proc -eq 3 ];then 213 | proc_manager restart #重启vsftpd服务. 214 | fi;; 215 | 6) 216 | exit;; 217 | *) 218 | $FAILURE 219 | echo "您的输入有误." 220 | $NORMAL 221 | exit;; 222 | esac 223 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ![image](https://github.com/jacobproject/Shell_Scripts/blob/master/cover/cover.jpg)
    2 | 图书《Linux Shell核心编程指南》的素材脚本。 3 | 4 | 《Linux Shell Scripts manual》 materials. 5 | 6 | The book's index: 7 | 8 | 第1章 从这里开始,起飞了 (page 1) 9 | Chaper1 Now begin! 10 | 11 | 12 | 13 | 1.1 脚本文件的书写格式 (page 1) 14 | The standard of Shell script. 15 | 16 | 1.2 脚本文件的各种执行方式 (page 3) 17 | How to run a Shell script. 18 | 19 | 1.3 如何在脚本文件中实现数据的输入与输出 (page 6) 20 | How read and write data through script. 21 | 22 | 1.4 输入与输出的重定向 (page 17) 23 | data redirection. 24 | 25 | 1.5 各种引号的正确使用姿势 (page 24) 26 | Quotation marks. 27 | 28 | 1.6 千变万化的变量 (page 28) 29 | Variables. 30 | 31 | 1.7 数据过滤与正则表达式 (page 33) 32 | Regular Expression. 33 | 34 | 1.8 各式各样的算术运算 (page 40) 35 | Basic operation. 36 | 37 | 38 |
    39 | 40 | 第2章 人工智能,很人工、很智能的脚本 (page 46) 41 | Chapter2 So smart script! 42 | 43 | 44 | 2.1 智能化脚本的基础之测试 (page 46) 45 | Test. 46 | 47 | 2.2 字符串的判断与比较 (page 47) 48 | Compare. 49 | 50 | 2.3 整数的判断与比较 (page 49) 51 | Integer comparison. 52 | 53 | 2.4 文件属性的判断与比较 (page 51) 54 | test file/directory. 55 | 56 | 2.5 探究[[]]和[]的区别 (page 55) 57 | Difference between [[]] and []. 58 | 59 | 2.6 实战案例:系统性能监控脚本 (page 60) 60 | Example: Monitoring system performance. 61 | 62 | 2.7 实战案例:单分支if语句 (page 62) 63 | Example: Simple examples of if. 64 | 65 | 2.8 实战案例:双分支if语句 (page 68) 66 | Example: More examples of if. 67 | 68 | 2.9 实战案例:如何监控HTTP服务状态 (page 72) 69 | Example: How to monitor http status. 70 | 71 | 2.10 实战案例:多分支if语句 (page 81) 72 | Example: Advanced if synopsis. 73 | 74 | 2.11 实战案例:简单、高效的case语句 (page 87) 75 | Example: Case synopsis. 76 | 77 | 2.12 实战案例:编写Nginx启动脚本 (page 92) 78 | Example: Nginx init.d script. 79 | 80 | 2.13 揭秘模式匹配与通配符、扩展通配符 (page 94) 81 | Pattern Martching、expended pattern. 82 | 83 | 2.14 Shell小游戏之石头剪刀布 (page 100) 84 | Game:Rock-paper-scissors. 85 | 86 | 87 | 88 |
    89 | 第3章 根本停不下来的循环和中断控制 (page 104) 90 | Chapter3 loop and break 91 | 92 | 93 | 3.1 玩转for循环语句 (page 104) 94 | for statement. 95 | 96 | 3.2 实战案例:猴子吃香蕉的问题 (page 114) 97 | Example: Monkey's problem. 98 | 99 | 3.3 实战案例:进化版HTTP状态监控脚本 (page 116) 100 | Example: Monitoring http status v2. 101 | 102 | 3.4 神奇的循环嵌套 (page 117) 103 | Nested loop. 104 | 105 | 3.5 非常重要的IFS (page 124) 106 | Important variable IFS. 107 | 108 | 3.6 实战案例:while循环 (page 130) 109 | Example: while statement. 110 | 111 | 3.7 Shell小游戏之猜随机数字 (page 134) 112 | Game: Guess the number. 113 | 114 | 3.8 实战案例:如何通过read命令读取文件中的数据 (page 136) 115 | Example: read data 116 | 117 | 3.9 until和select循环 (page 140) 118 | untile and select. 119 | 120 | 3.10 中断与退出控制 (page 143) 121 | break and exit. 122 | 123 | 3.11 Shell小游戏之机选双色球 (page 149) 124 | Game: Lottery. 125 | 126 | 127 | 128 |
    129 | 第4章 请开始你的表演,数组、Subshell与函数 (page 152) 130 | Chapter4 Array、subshell and function. 131 | 132 | 133 | 4.1 强悍的数组 (page 152) 134 | Array. 135 | 136 | 4.2 实战案例:斐波那契数列 (page 157) 137 | Example: Fibonacci sequence. 138 | 139 | 4.3 实战案例:网站日志分析脚本 (page 159) 140 | Example: Analysis web log. 141 | 142 | 4.4 常犯错误的SubShell (page 164) 143 | The subshell. 144 | 145 | 4.5 启动进程的若干种方式 (page 172) 146 | How to run a new program. 147 | 148 | 4.6 非常实用的函数功能 (page 176) 149 | Function. 150 | 151 | 4.7 变量的作用域与return返回值 (page 179) 152 | Scope of variable、return. 153 | 154 | 4.8 实战案例:多进程的ping脚本 (page 185) 155 | Example: Multi process script for ping. 156 | 157 | 4.9 控制进程数量的核心技术——文件描述符和命名管道 (page 187) 158 | File descriptor and named pipe. 159 | 160 | 4.10 实战案例:一键源码部署LNMP的脚本 (page 197) 161 | Example: Install LNMP software through Shell. 162 | 163 | 4.11 递归函数 (page 204) 164 | Recursive function. 165 | 166 | 4.12 排序算法之冒泡排序 (page 206) 167 | Bubble sort. 168 | 169 | 4.13 排序算法之快速排序 (page 209) 170 | Quick sort. 171 | 172 | 4.14 排序算法之插入排序 (page 213) 173 | Insertion sort. 174 | 175 | 4.15 排序算法之计数排序 (page 215) 176 | Counting sort. 177 | 178 | 4.16 Shell小游戏之单词拼接puzzle (page 218) 179 | Game: puzzle. 180 | 181 | 182 | 183 |
    184 | 第5章 一大波脚本技巧正向你走来 (page 221) 185 | Chapter5 Skill. 186 | 187 | 188 | 5.1 Shell八大扩展功能之花括号 (page 221) 189 | {}Curly braces. 190 | 191 | 5.2 Shell八大扩展功能之波浪号 (page 223) 192 | ~Tilde. 193 | 194 | 5.3 Shell八大扩展功能之变量替换 (page 224) 195 | Variable substitution. 196 | 197 | 5.4 Shell八大扩展功能之命令替换 (pgae 234) 198 | Command substitution. 199 | 200 | 5.5 Shell八大扩展功能之算术替换 (page 234) 201 | Operation substitution. 202 | 203 | 5.6 Shell八大扩展功能之进程替换 (page 236) 204 | Process substitution. 205 | 206 | 5.7 Shell八大扩展功能之单词切割 (page 238) 207 | Word spliting. 208 | 209 | 5.8 Shell八大扩展功能之路径替换 (page 239) 210 | Path substitution. 211 | 212 | 5.9 实战案例:生成随机密码的若干种方式 (page 240) 213 | Example: Random password. 214 | 215 | 5.10 Shell解释器的属性与初始化命令行终端 (page 247) 216 | Bash attribution. 217 | 218 | 5.11 trap信号捕获 (page 257) 219 | trap. 220 | 221 | 5.12 实战案例:电子时钟 (page 259) 222 | Example: Clock. 223 | 224 | 5.13 Shell小游戏之抓住小老鼠算你赢 (page 263) 225 | Game: Catch a mouse. 226 | 227 | 5.14 实战案例:脚本排错技巧 (page 267) 228 | Example: debug. 229 | 230 | 5.15 实战案例:Shell版本的进度条功能 (page 270) 231 | Example: Progress bar. 232 | 233 | 5.16 再谈参数传递之xargs (page 276) 234 | xargs 235 | 236 | 5.17 使用shift移动位置参数 (page 280) 237 | shift. 238 | 239 | 5.18 实战案例:Nginx日志切割脚本 (page 281) 240 | Example: Nginx log. 241 | 242 | 243 | 244 |
    245 | 第6章 上古神兵利器sed (page 285) 246 | Chapter6 sed. 247 | 248 | 6.1 sed基本指令 (page 285) 249 | Basic syntax. 250 | 251 | 6.2 sed高级指令 (page 305) 252 | Advanced sed. 253 | 254 | 6.3 实战案例:自动化配置vsftpd脚本 (page 318) 255 | Example: Configure vsftpd serivce. 256 | 257 | 6.4 实战案例:自动化配置DHCP脚本 (page 325) 258 | Example: Configure dhcp service. 259 | 260 | 6.5 实战案例:自动化克隆KVM虚拟机脚本 (page 329) 261 | Example: Clone kvm virtual machine. 262 | 263 | 6.6 实战案例:通过libguestfs管理KVM虚拟机脚本 (page 337) 264 | Example: libguestfs. 265 | 266 | 6.7 实战案例:自动化配置SSH安全策略脚本 (pgae 343) 267 | Example: Configure ssh service. 268 | 269 | 6.8 实战案例:基于GRUB配置文件修改内核启动参数脚本 (page 345) 270 | Example: Modify grub.cfg. 271 | 272 | 6.9 实战案例:网络爬虫脚本 (page 348) 273 | Example: Internet Worm. 274 | 275 | 6.10 Shell小游戏之点名抽奖器 (page 354) 276 | Game:Roll call. 277 | 278 | 279 | 280 |
    281 | 第7章 不可思议的编程语言awk (page 356) 282 | Chapter7 awk. 283 | 284 | 7.1 awk基础语法 (page 356) 285 | awk syntax. 286 | 287 | 7.2 awk条件判断 (page 374) 288 | if statement. 289 | 290 | 7.3 awk数组与循环 (page 379) 291 | array and loop. 292 | 293 | 7.4 awk函数 (page 388) 294 | awk funcation. 295 | 296 | 7.5 实战案例:awk版网站日志分析 (page 398) 297 | Example: Analysis web log. 298 | 299 | 7.6 实战案例:监控网络连接状态 (page 403) 300 | Example: Monitoring network connection status. 301 | 302 | 7.7 实战案例:获取SSH暴力破解攻击黑名单列表 (page 412) 303 | Example: Generate block user file. 304 | 305 | 7.8 实战案例:性能监控脚本 (page 418) 306 | Example: Monitoring system performance. 307 | 308 | 7.9 实战案例:数据库监控脚本 (page 420) 309 | Example: Monitoring MySQL. 310 | 311 | 7.10 实战案例:awk版网络爬虫 (page 429) 312 | Example: Internet Worm. 313 | -------------------------------------------------------------------------------- /chaper07/blockip.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | #功能描述(Description):分析系统登陆日志,过滤异常IP地址,并通过防火墙禁用该IP. 3 | 4 | #强制退出时关闭所有后台进程. 5 | trap 'kill $one_pid; kill $five_pid; kill $fifteen_pid; exit' EXIT INT 6 | 7 | #日志文件路径. 8 | LOGFILE=/var/log/secure 9 | BLOCKFILE=/tmp/blockip.txt 10 | 11 | one_minute(){ 12 | while : 13 | do 14 | #获取计算机当前时间,以及1分钟前的时间,时间格式: 15 | #%b(月份简写,Jan) %e(日期,1) %T(时间 18:00:00) 16 | #LANG=C的作用是否防止输出中文. 17 | #使用local定义局部变量的好处是多个函数使用相同的变量名也不会冲突. 18 | local curtime_month=$(LANG=C date +"%b") 19 | local curtime_day=$(LANG=C date +"%e") 20 | local curtime_time=$(LANG=C date +"%T") 21 | local one_minus_ago=$(LANG=C date -d "1 minutes ago" +"%T") 22 | #将当前时间转换为距离1970-01-01 00:00:00的秒数,方便后期计算. 23 | local curtime_seconds=$(LANG=C date +"%s") 24 | #分析1分钟内所有的日志,如果密码失败则过滤倒数第4列的IP地址. 25 | #通过管道对过滤的IP进行计数统计,提取密码失败次数大于等于3次的IP地址. 26 | #awk调用外部Shell的变量时,双引号在外面表示字符串("''"),单引号在外边表示数字('""'). 27 | pass_fail_ip=$(awk ' 28 | $1=="'$curtime_month'" && \ 29 | $2=='"$curtime_day"' && \ 30 | $3>="'$one_minus_ago'" && \ 31 | $3<="'$curtime_time'" \ 32 | { if($6=="Failed" && $9!="invalid") {print $(NF-3)}}' $LOGFILE | \ 33 | awk '{IP[$1]++} END{ for(i in IP){ if(IP[i]>=3) {print i} } }') 34 | #将密码失败次数大于3次的IP写入黑名单文件, 35 | #每次写入前都需要判断黑名单中是否已经存在该IP. 36 | #写入黑名单时附加时间标记,实现仅将IP放入黑名单特定的时间, 37 | #如:密码失败3次后,禁止该IP在20分钟内再次访问服务器. 38 | for i in $pass_fail_ip 39 | do 40 | if ! grep -q "$i" $BLOCKFILE ;then 41 | echo "$curtime_seconds $i" >> $BLOCKFILE 42 | fi 43 | done 44 | #提取无效账户登陆服务器3次的IP地址,并将其加入黑名单. 45 | user_invalid_ip=$(awk ' 46 | $1=="'$curtime_month'" && \ 47 | $2=='"$curtime_day"' && \ 48 | $3>="'$one_minus_ago'" && \ 49 | $3<="'$curtime_time'" \ 50 | { if($6=="Invalid") {print $(NF-2)}}' $LOGFILE | \ 51 | awk '{IP[$1]++} END{ for(i in IP){ if(IP[i]>=3) {print i} } }') 52 | for j in $user_invalid_ip 53 | do 54 | if ! grep -q "$j" $BLOCKFILE ;then 55 | echo "$curtime_seconds $j" >> $BLOCKFILE 56 | fi 57 | done 58 | sleep 60 59 | done 60 | } 61 | 62 | five_minutes(){ 63 | while : 64 | do 65 | #获取计算机当前时间,以及5分钟前的时间,时间格式: 66 | #%b(月份简写,Jan) %e(日期,1) %T(时间 18:00:00) 67 | #使用local定义局部变量的好处是多个函数使用相同的变量名也不会冲突. 68 | local curtime_month=$(LANG=C date +"%b") 69 | local curtime_day=$(LANG=C date +"%e") 70 | local curtime_time=$(LANG=C date +"%T") 71 | local one_minus_ago=$(LANG=C date -d "5 minutes ago" +"%T") 72 | #将当前时间转换为距离1970-01-01 00:00:00的秒数,方便后期计算. 73 | local curtime_seconds=$(LANG=C date +"%s") 74 | #分析5分钟内所有的日志,提取3次密码错误的IP地址并加入黑名单. 75 | pass_fail_ip=$(awk ' 76 | $1=="'$curtime_month'" && \ 77 | $2=='"$curtime_day"' && \ 78 | $3>="'$one_minus_ago'" && \ 79 | $3<="'$curtime_time'" \ 80 | { if($6=="Failed" && $9!="invalid") {print $(NF-3)}}' $LOGFILE | \ 81 | awk '{IP[$1]++} END{ for(i in IP){ if(IP[i]>=3) {print i} } }') 82 | for i in $pass_fail_ip 83 | do 84 | if ! grep -q "$i" $BLOCKFILE ;then 85 | echo "$curtime_seconds $i" >> $BLOCKFILE 86 | fi 87 | done 88 | #提取错误用户名登陆服务器3次的IP地址,并将其加入黑名单. 89 | user_invalid_ip=$(awk ' 90 | $1=="'$curtime_month'" && \ 91 | $2=='"$curtime_day"' && \ 92 | $3>="'$one_minus_ago'" && \ 93 | $3<="'$curtime_time'" \ 94 | { if($6=="Invalid") {print $(NF-2)}}' $LOGFILE | \ 95 | awk '{IP[$1]++} END{ for(i in IP){ if(IP[i]>=3) {print i} } }') 96 | for j in $user_invalid_ip 97 | do 98 | if ! grep -q "$j" $BLOCKFILE ;then 99 | echo "$curtime_seconds $j" >> $BLOCKFILE 100 | fi 101 | done 102 | sleep 300 103 | done 104 | } 105 | 106 | fifteen_minutes(){ 107 | while : 108 | do 109 | #获取计算机当前时间,以及15分钟前的时间,时间格式: 110 | #%b(月份简写,Jan) %e(日期,1) %T(时间 18:00:00) 111 | #使用local定义局部变量的好处是多个函数使用相同的变量名也不会冲突. 112 | local curtime_month=$(LANG=C date +"%b") 113 | local curtime_day=$(LANG=C date +"%e") 114 | local curtime_time=$(LANG=C date +"%T") 115 | local one_minus_ago=$(LANG=C date -d "15 minutes ago" +"%T") 116 | #将当前时间转换为距离1970-01-01 00:00:00的秒数,方便后期计算. 117 | local curtime_seconds=$(LANG=C date +"%s") 118 | #分析15分钟内所有的日志,提取3次密码错误的IP地址并加入黑名单. 119 | pass_fail_ip=$(awk ' 120 | $1=="'$curtime_month'" && \ 121 | $2=='"$curtime_day"' && \ 122 | $3>="'$one_minus_ago'" && \ 123 | $3<="'$curtime_time'" \ 124 | { if($6=="Failed" && $9!="invalid") {print $(NF-3)}}' $LOGFILE | \ 125 | awk '{IP[$1]++} END{ for(i in IP){ if(IP[i]>=3) {print i} } }') 126 | for i in $pass_fail_ip 127 | do 128 | if ! grep -q "$i" $BLOCKFILE ;then 129 | echo "$curtime_seconds $i" >> $BLOCKFILE 130 | fi 131 | done 132 | #提取错误用户名登陆服务器3次的IP地址,并将其加入黑名单. 133 | user_invalid_ip=$(awk ' 134 | $1=="'$curtime_month'" && \ 135 | $2=='"$curtime_day"' && \ 136 | $3>="'$one_minus_ago'" && \ 137 | $3<="'$curtime_time'" \ 138 | { if($6=="Invalid") {print $(NF-2)}}' $LOGFILE | \ 139 | awk '{IP[$1]++} END{ for(i in IP){ if(IP[i]>=3) {print i} } }') 140 | for j in $user_invalid_ip 141 | do 142 | if ! grep -q "$j" $BLOCKFILE ;then 143 | echo "$curtime_seconds $j" >> $BLOCKFILE 144 | fi 145 | done 146 | sleep 1200 147 | done 148 | } 149 | 150 | #每隔20分钟检查一次黑名单,清理大于20分钟的黑名单IP. 151 | clear_blockip(){ 152 | while : 153 | do 154 | sleep 1200 155 | #将当前时间转换为距离1970-01-01 00:00:00的秒数,方便后期计算. 156 | local curtime_seconds=$(LANG=C date +"%s") 157 | #awk调用外部shell变量的另一种方式是使用-v选项. 158 | #当前时间减去黑名单中的时间标记,大于等于1200秒(20分钟)则将其从黑名单中删除. 159 | tmp=$(awk -v now=$curtime_seconds '(now-$1)>=1200 {print $2}' $BLOCKFILE) 160 | for i in $tmp 161 | do 162 | sed -i "/$i/d" $BLOCKFILE 163 | done 164 | done 165 | } 166 | 167 | > $BLOCKFILE 168 | one_minute & 169 | one_pid="$!" 170 | five_minutes & 171 | five_pid="$!" 172 | fifteen_minutes & 173 | fifteen_pid="$!" 174 | clear_blockip 175 | -------------------------------------------------------------------------------- /chaper04/lnmp.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | #功能描述(Description):一键部署LNMP环境. 3 | #执行脚本时需要在当前目录下有:nginx-1.14.2.tar.gz,mysql-boost-8.0.13.tar.gz,php-7.3.0.tar.gz. 4 | 5 | #设置各种显示消息的颜色属性. 6 | SETCOLOR_SUCCESS="echo -en \\033[1;32m" 7 | SETCOLOR_FAILURE="echo -en \\033[1;31m" 8 | SETCOLOR_WARNING="echo -en \\033[1;34m" 9 | SETCOLOR_NORMAL="echo -e \\033[0;39m" 10 | 11 | #测试yum源是否可用,awk和sed的用法在后面章节中有介绍. 12 | test_yum(){ 13 | yum clean all &>/dev/null 14 | num=$(yum repolist -e 0 | awk '/repolist/{print $2}' | sed 's/,//') 15 | if [ $num -le 0 ];then 16 | $SETCOLOR_FAILURE 17 | echo -n "[ERROR]:没有YUM源!" 18 | $SETCOLOR_NORMAL 19 | exit 20 | fi 21 | } 22 | 23 | #安装LNMP环境所需要的依赖包. 24 | install_deps(){ 25 | yum -y install gcc pcre-devel openssl-devel cmake ncurses-devel gcc-c++ bison bison-devel 26 | yum -y install libxml2 libxml2-devel curl curl-devel libjpeg libjpeg-devel freetype gd gd-devel 27 | yum -y install freetype-devel libxslt libxslt-devel bzip2 bzip2-devel libpng libpng-devel 28 | } 29 | 30 | #源码安装Nginx:创建账户,激活需要的模块,禁用不需要的模块. 31 | install_nginx(){ 32 | if ! id nginx &>/dev/null ;then 33 | useradd -s /sbin/nologin nginx 34 | fi 35 | tar -xf nginx-1.14.2.tar.gz 36 | cd nginx-1.14.2 37 | ./configure --prefix=/usr/local/nginx \ 38 | --user=nginx --group=nginx \ 39 | --with-http_stub_status_module \ 40 | --with-stream \ 41 | --with-http_realip_module \ 42 | --with-http_ssl_module \ 43 | --without-http_autoindex_module \ 44 | --without-mail_pop3_module \ 45 | --without-mail_imap_module \ 46 | --without-mail_smtp_module 47 | $SETCOLOR_WARNING 48 | echo -n "正在编译Nginx,请耐心等待..." 49 | $SETCOLOR_NORMAL 50 | make &>/dev/null && make install &>/dev/null 51 | cd .. 52 | ln -s /usr/local/nginx/sbin/nginx /usr/sbin/nginx 53 | } 54 | 55 | #默认源码安装的软件没有service文件无法通过systemd管理. 56 | #手动编写service文件,方便在CentOS7的环境中管理服务. 57 | conf_nginx_systemd(){ 58 | cat > /usr/lib/systemd/system/nginx.service <<- EOF 59 | [Unit] 60 | Description=nginx 61 | After=syslog.target network.target 62 | 63 | [Service] 64 | Type=forking 65 | PIDFile=/usr/local/nginx/logs/nginx.pid 66 | ExecStartPre=/usr/sbin/nginx -t 67 | ExecStart=/usr/local/nginx/sbin/nginx 68 | ExecReload=/usr/sbin/nginx -s reload 69 | ExecStop=/bin/kill -s QUIT $MAINPID 70 | 71 | [Install] 72 | WantedBy=multi-user.target 73 | EOF 74 | } 75 | 76 | #源码安装部署MySQL8.0版本的数据库软件. 77 | #注意:需要提前到官网下载带boost版本的MySQL(mysql-boost-8.0.13.tar.gz). 78 | install_mysql8(){ 79 | if ! id mysql &>/dev/null ;then 80 | useradd -s /sbin/nologin mysql 81 | fi 82 | tar -xf mysql-boost-8.0.13.tar.gz 83 | cd mysql-8.0.13/ 84 | $SETCOLOR_WARNING 85 | echo "请确保有超过2G的可用内存,否则编译可能出错,并提示Killed (程序 cc1plus)" 86 | echo -n "编译MySQL需要一个漫长的过程,请耐心等待." 87 | $SETCOLOR_NORMAL 88 | sleep 5 89 | cmake . -DCMAKE_INSTALL_PREFIX=/usr/local/mysql -DDEFAULT_CHARSET=utf8mb4 -DDEFAULT_COLLATION=utf8_general_ci -DENABLED_LOCAL_INFILE=ON -DWITH_INNOBASE_STORAGE_ENGINE=1 -DWITH_FEDERATED_STORAGE_ENGINE=1 -DWITH_BLACKHOLE_STORAGE_ENGINE=1 -DWITHOUT_EXAMPLE_STORAGE_ENGINE=1 -DWITH_PARTITION_STORAGE_ENGINE=1 -DWITH_PERFSCHEMA_STORAGE_ENGINE=1 -DWITH_BOOST=./boost -DSYSCONFDIR=/etc/ -DMYSQL_UNIX_ADDR=/tmp/mysql.sock 90 | #DCMAKE_INSTALL_PREFIX:指定安装路径. 91 | #DDEFAULT_CHARSET:设置默认字符集. 92 | #DDEFAULT_COLLATION:默认的字符集序,决定了字符的排列顺序. 93 | #DENABLED_LOCAL_INFILE:允许通过本地文件导入数据库. 94 | #DWITH_INNOBASE_STORAGE_ENGINE:开启INNODB存储引擎. 95 | #DWITH_FEDERATED_STORAGE_ENGINE:开启FEDERATED存储引擎,支持远程数据库. 96 | #DWITH_BLACKHOLE_STORAGE_ENGINE:开启BLACKHOLE黑洞存储引擎,主从同步进行多级复制时使用. 97 | #DWITHOUT_EXAMPLE_STORAGE_ENGINE:禁用EXAMPLE存储引擎. 98 | #DWITH_PARTITION_STORAGE_ENGINE:开启PARTITION分区存储引擎. 99 | #DWITH_PERFSCHEMA_STORAGE_ENGINE:开启PERFSCHEMA存储引擎. 100 | #DWITH_BOOST:指定BOOST程序的目录位置. 101 | #DSYSCONFDIR:指定配置文件目录. 102 | #DMYSQL_UNIX_ADDR:指定sock文件位置. 103 | make -j 5 #多进程编译. 104 | make install 105 | chown -R mysql.mysql /usr/local/mysql/ 106 | mkdir /var/log/mariadb 107 | touch /var/log/mariadb/mariadb.log 108 | chown -R mysql.mysql /var/log/mariadb/ 109 | mkdir -p /var/lib/mysql/data/ 110 | chown -R mysql.mysql /var/lib/mysql/ 111 | ln -s /usr/local/mysql/bin/* /bin/ 112 | cat > /etc/ld.so.conf.d/mysql.conf <<- EOF 113 | /usr/local/mysql/lib 114 | EOF 115 | cd .. 116 | } 117 | 118 | init_mysql8(){ 119 | #创建MySQL配置文件(设置socket文件,数据库目录,以及优化等参数). 120 | cat > /etc/my.cnf <<- EOF 121 | [client] 122 | port = 3306 123 | socket = /tmp/mysql.sock 124 | 125 | [mysqld] 126 | port = 3306 127 | socket = /tmp/mysql.sock 128 | datadir = /var/lib/mysql/data 129 | skip-external-locking 130 | key_buffer_size = 16M 131 | max_allowed_packet = 1M 132 | table_open_cache = 64 133 | sort_buffer_size = 512K 134 | net_buffer_length = 16K 135 | read_buffer_size = 256K 136 | read_rnd_buffer_size = 512K 137 | myisam_sort_buffer_size = 8M 138 | thread_cache_size = 8 139 | tmp_table_size = 16M 140 | performance_schema_max_table_instances = 500 141 | back_log = 3000 142 | binlog_cache_size = 2048KB 143 | binlog_checksum = CRC32 144 | binlog_order_commits = ON 145 | binlog_rows_query_log_events = OFF 146 | binlog_row_image = full 147 | binlog_stmt_cache_size = 32768 148 | block_encryption_mode = "aes-128-ecb" 149 | bulk_insert_buffer_size = 4194304 150 | character_set_filesystem = binary 151 | character_set_server = utf8mb4 152 | default_time_zone = SYSTEM 153 | default_week_format = 0 154 | delayed_insert_limit = 100 155 | delayed_insert_timeout = 300 156 | delayed_queue_size = 1000 157 | delay_key_write = ON 158 | disconnect_on_expired_password = ON 159 | range_alloc_block_size = 4096 160 | range_optimizer_max_mem_size = 8388608 161 | table_definition_cache = 512 162 | table_open_cache = 2000 163 | table_open_cache_instances = 1 164 | thread_cache_size = 100 165 | thread_stack = 262144 166 | explicit_defaults_for_timestamp = true 167 | #skip-networking 168 | max_connections = 10000 169 | max_connect_errors = 100 170 | open_files_limit = 65535 171 | log-bin = mysql-bin 172 | binlog_format = mixed 173 | server-id = 1 174 | binlog_expire_logs_seconds = 864000 175 | early-plugin-load = "" 176 | 177 | default_storage_engine = InnoDB 178 | innodb_file_per_table = 1 179 | innodb_data_home_dir = /var/lib/mysql/data 180 | innodb_data_file_path = ibdata1:10M:autoextend 181 | innodb_log_group_home_dir = /var/lib/mysql/data 182 | innodb_buffer_pool_size = 16M 183 | innodb_log_file_size = 5M 184 | innodb_log_buffer_size = 8M 185 | innodb_flush_log_at_trx_commit = 1 186 | innodb_lock_wait_timeout = 50 187 | 188 | [mysqldump] 189 | quick 190 | max_allowed_packet = 16M 191 | 192 | [mysql] 193 | no-auto-rehash 194 | 195 | [myisamchk] 196 | key_buffer_size = 20M 197 | sort_buffer_size = 20M 198 | read_buffer = 2M 199 | write_buffer = 2M 200 | EOF 201 | #初始化MySQL数据库. 202 | /usr/local/mysql/bin/mysqld --initialize-insecure \ 203 | --basedir=/usr/local/mysql \ 204 | --datadir=/var/lib/mysql/data/ \ 205 | --user=mysql 206 | #拷贝启动脚本. 207 | cp /usr/local/mysql/support-files/mysql.server /etc/init.d/mysqld 208 | } 209 | 210 | install_php7(){ 211 | useradd -s /sbin/nologin www 212 | tar -xf php-7.3.0.tar.gz 213 | cd php-7.3.0 214 | ./configure --prefix=/usr/local/php \ 215 | --enable-fpm \ 216 | --with-fpm-user=www --with-fpm-group=www \ 217 | --with-curl --with-freetype-dir \ 218 | --with-gd --with-gettext \ 219 | --with-iconv-dir \ 220 | --with-libdir=lib64 221 | --with-libxml-dir \ 222 | --with-mysqli \ 223 | --with-pdo-mysql \ 224 | --with-openssl \ 225 | --with-pcre-regex \ 226 | --with-pdo-sqlite \ 227 | --with-pear --with-png-dir \ 228 | --with-xmlrpc --with-xsl \ 229 | --with-zlib --enable-bcmath \ 230 | --enable-libxml \ 231 | --enable-inline-optimization \ 232 | --enable-mbregex --enable-mbstring \ 233 | --enable-opcache --enable-pcntl \ 234 | --enable-shmop --enable-soap \ 235 | --enable-sockets --enable-sysvsem --enable-xml 236 | make -j 5 237 | make install 238 | cp php.ini-production /usr/local/php/etc/php.ini 239 | sed -i 's#;date.timezone =#date.timezone = Asia/Shanghai#' /usr/local/php/etc/php.ini 240 | sed -i 's#max_execution_time = .*#max_execution_time = 300#' /usr/local/php/etc/php.ini 241 | sed -i 's#post_max_size =.*#post_max_size = 32M#' /usr/local/php/etc/php.ini 242 | sed -i 's#max_input_time = .*#max_input_time = 300#' /usr/local/php/etc/php.ini 243 | cp sapi/fpm/php-fpm.service /usr/lib/systemd/system/ 244 | ln -s /usr/local/php/sbin/php-fpm /usr/sbin/ 245 | ln -s /usr/local/php/bin/* /bin/ 246 | cp /usr/local/php/etc/{php-fpm.conf.default,php-fpm.conf} 247 | cp /usr/local/php/etc/php-fpm.d/{www.conf.default,www.conf} 248 | cd .. 249 | } 250 | 251 | #调用执行函数,安装部署LNMP环境. 252 | test_yum 253 | install_deps 254 | install_nginx 255 | conf_nginx_systemd 256 | install_mysql8 257 | init_mysql8 258 | install_php7 259 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "{}" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright {yyyy} {name of copyright owner} 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | --------------------------------------------------------------------------------