shell脚本通过日志来统计网站pv 404 500状态码

下面的脚本能统计出网站的总访问量,以及404,500出现的次数。统计出来后,我们可以结合监控宝来进行记录,进而可以看出网站访问量是否异常,是否存在攻击,一目了然。还可以根据查看500出现的次数,进而判断网站程序是否出现异常。

  1. #!/bin/bash
  2. #purpose:count nginx or apache or other webserver status code using jiankongbao
  3. #how to:run the script every 5 minutes with crontab
  4. #write by zhumaohai.
  5. #blog: http://devops.webres.wang/
  6.  
  7. log_path="/var/log/nginx/devops.webres.wang/access.log"
  8. becur=`date -d "5 minute ago" +%H%M%S`
  9. code=(`tac $log_path  | awk  -v a="$becur" -v total=0 -F [‘ ‘:] ‘{
  10. t=$5$6$7
  11. if (t>=a){
  12. code[$12]++
  13. total++
  14. }
  15. else {
  16. exit;
  17. }
  18. }END{
  19. print code[404]?code[404]:0,code[500]?code[500]:0,total
  20. }’
  21. `)
  22. c404=${code[0]}
  23. c500=${code[1]}
  24. total=${code[2]}
  25. echo -e "<pre>nc404:${c404}nc500:${c500}ntotal:${total}n</pre>" > /data/www/status/devops.webres.wang.html

脚本最后一行是以:

  1. <pre>
  2. c404:1102
  3. c500:545
  4. total:55463
  5. </pre>

的格式写入到一个devops.webres.wang html文件,再结合监控宝的自定义监控来收集这些信息。
非常的方便,监控宝会自动出图表。

同时管理多台服务器的expect脚本

最近通过exploring expect书籍,简单学了下expect脚本语言,这个脚本语言是tcl语言的扩展,用来解决一些工具无法自动交互的问题,如ssh登录时,无法在命令就指定密码等。下面是利用expect来实现管理多台服务器的简单例子:

  1. #!/usr/bin/expect
  2. #purpose:auto run command on multiple servers
  3. #how to:  mms <user> <cmd>
  4. #write by zhumaohai.
  5. #blog:http://devops.webres.wang/
  6.  
  7. if {$argc < 2} {
  8. puts "usage: mms <user> <cmd>"
  9. exit 1
  10. }
  11.  
  12. #set servers
  13. set SERVERS {"192.168.0.100" "192.168.0.101" "192.168.0.102"}
  14.  
  15. #set password
  16. set PASSWORDS(user1) "passwd1"
  17. set PASSWORDS(user2) "passwd2"
  18.  
  19. #get virables
  20. set USER [lindex $argv 0]
  21. set CMD [lrange $argv 1 end]
  22.  
  23. set passwd $PASSWORDS($USER)
  24.  
  25. foreach x $SERVERS {
  26. eval spawn ssh -l $USER $x $CMD
  27. expect {
  28. "password" { send "$passwdr" }
  29. "yes/no" { send "yesr";exp_continue; }
  30. }
  31. expect eof
  32. }

1、这里定义了三台服务器192.168.0.100 192.168.0.101 192.168.0.102,定义了用户user1的密码为passwd1,用户user2的密码为passwd2,假如脚本文件名为ms,用法为:
./ms 用户 命令
如./ms user1 date
2、在使用脚本时,请确认系统已经安装有expect命令,centos使用yum install expect安装,ubuntu使用apt-get install expect安装。

shell数组小结

数组作为一种特殊的数据结构在任何一种编程语言中都有它的一席之地,当然bash shell也不例外。本文就shell数组来做一个小的总结。
在这里只讨论一维数组的情况,关于多维数组(事实上,你得用一维数组的方法来模拟),不涉及。这里包括数组的复制,计算,删除,替换。

数组的声明:

  1. 1)array[key]=value # array[0]=one,array[1]=two
  1. 2)declare -a array # array被当作数组名
  1. 3)array=( value1 value2 value3 … )
  1. 4)array=( [1]=one [2]=two [3]=three … )
  1. 5)array="one two three" # echo ${array[0|@|*]},把array变量当作数组来处理,但数组元素只有字符串本身

数组的访问:

  1. 1)${array[key]} # ${array[1]}

数组的删除

  1. 1)unset array[1] # 删除数组中第一个元素
  1. 2)unset array # 删除整个数组

计算数组的长度:

  1. 1)${#array}
  1. 2)${#array[0]} #同上。 ${#array[*]} 、${#array[@]}。注意同#{array:0}的区别

数组的提取
从尾部开始提取:

  1. array=( [0]=one [1]=two [2]=three [3]=four )
  2. ${array[@]:1} # two three four,除掉第一个元素后所有元素,那么${array[@]:0}表示所有元素
  3. ${array[@]:0:2} # one two
  4. ${array[@]:1:2} # two three

子串删除

  1. [root@localhost dev]# echo ${array[@]:0}
  2. one two three four
  3.  
  4. [root@localhost dev]# echo ${array[@]#t*e} # 左边开始最短的匹配:"t*e",这将匹配到"thre"
  5. one two e four
  6.  
  7. [root@localhost dev]# echo ${array[@]##t*e} # 左边开始最长的匹配,这将匹配到"three"
  8.  
  9. [root@localhost dev]# array=( [0]=one [1]=two [2]=three [3]=four )
  10.  
  11. [root@localhost dev]# echo ${array[@] %o} # 从字符串的结尾开始最短的匹配
  12. one tw three four
  13.  
  14. [root@localhost dev]# echo ${array[@] %%o} # 从字符串的结尾开始最长的匹配
  15. one tw three four

子串替换

  1. [root@localhost dev]# array=( [0]=one [1]=two [2]=three [3]=four )

第一个匹配到的,会被删除

  1. [root@localhost dev]# echo ${array[@] /o/m}
  2. mne twm three fmur

所有匹配到的,都会被删除

  1. [root@localhost dev]# echo ${array[@] //o/m}
  2. mne twm three fmur

没有指定替换子串,则删除匹配到的子符

  1. [root@localhost dev]# echo ${array[@] //o/}
  2. ne tw three fur

替换字符串前端子串

  1. [root@localhost dev]# echo ${array[@] /#o/k}
  2. kne two three four

替换字符串后端子串

  1. [root@localhost dev]# echo ${array[@] /%o/k}
  2. one twk three four

转自:http://bbs.chinaunix.net/thread-1779167-1-1.html

自动重启服务shell脚本

比如我们想重启php-fpm。

  1. #!/bin/bash
  2.  
  3. #变量初始化
  4. process="php-fpm" #进程名
  5. startCmd="/etc/init.d/php-fpm start" #启动命令
  6. down=0
  7.  
  8. while true
  9. do
  10.     #取得http状态码
  11.     code=$(curl -H "Host:devops.webres.wang" -m 5 -L -s -w %{http_code} http://127.0.0.1 -o /dev/null)
  12.     #当状态码返回000或者大于等于500时,计数故障到down变量
  13.     if [ $code -eq 000 -o $code -ge 500 ];then
  14.         ((down++))
  15.     else
  16. break
  17.     fi
  18.     #稍等5s
  19.     sleep 5
  20.     #判断是否连续检测三次都为故障.
  21.     if [ $down -ge 3 ];then
  22. if [ "$(find /tmp/${process}_restart -mmin -3)" == "" ];then
  23.                 #取得进程名对应的所有pid
  24. pids=$(ps aux | grep ${process} | grep -v "grep" | awk ‘{print $2}’)
  25.                 #依次对所有pid执行kill命令
  26. for i in $pids;do
  27. kill -9 $i
  28. kill -9 $i
  29. done
  30.                 #kill完pid后,启动服务
  31. $startCmd
  32. echo "$(date) Return code $code,${process} had been restarted" >> /tmp/${process}_restart
  33. else
  34. echo "$(date) ${process} not yet recovery.As it had been restarted in 2 minutes.so this time ignore." >> /tmp/${process}_not_restart
  35. fi
  36.  
  37. break
  38.     fi
  39. done

防止端口扫描shell脚本

网上有现在的防端口工具,如psad、portsentry,但觉得配置有点麻烦,且服务器不想再装一个额外的软件。所以自己就写了个shell脚本实现这个功能。基本思路是:使用iptables的recent模块记录下在60秒钟内扫描超过10个端口的IP,并结合inotify-tools工具实时监控iptables的日志,一旦iptables日志文件有写入新的ip记录,则使用iptables封锁源ip,起到了防止端口扫描的功能。 继续阅读防止端口扫描shell脚本

shell脚本每天自动统计网站访问日志

写了个shell脚本,可以用来统计每天的访问日志,并发送到电子邮箱,方便每天了解网站情况。
脚本统计了:
1、总访问量
2、总带宽
3、独立访客量
4、访问IP统计
5、访问url统计
6、来源统计
7、404统计
8、搜索引擎访问统计(谷歌,百度)
9、搜索引擎来源统计(谷歌,百度)
继续阅读shell脚本每天自动统计网站访问日志

使用shell脚本自动配置mysql主从

一直觉得配置mysql的主从挺费时间,现在花了一点时间写了个全自动配置mysql主从的shell脚本。如有什么错误,欢迎提出。
1、在使用之前需要在主服务器上编辑/etc/my.cnf文件,在[mysqld]的下面加入下面代码:

  1. log-bin=mysql-bin
  2. server-id=1
  3. innodb_flush_log_at_trx_commit=1
  4. sync_binlog=1
  5. binlog-do-db=centos
  6. binlog_ignore_db=mysql

server-id=1中的1可以任定义,只要是唯一的并且比从服务器的server-id小就行。
binlog-do-db=centos是表示binlog只记录centos数据库的日志,即只同步centos。
binlog_ignore_db=mysql表示忽略备份mysql。
不加binlog-do-db和binlog_ignore_db,那就表示备份全部数据库。
2、在从服务器编辑配置文件my.cnf,在[mysqld]下面加入:

  1. server-id=2

2可以自己定义,只要保证唯一的并且比主的server-id大就行。
3、脚本分为两个,一个是配置mysql主服务器的shell脚本,另一个是远程连接mysql从服务器的exp脚本。
bash shell脚本:master.sh

  1. #!/bin/bash
  2.  
  3. export mysqlbinpath="/usr/bin" #mysql路径
  4.  
  5. #variables for master
  6. export master_mysql_root_passwd="root"  #mysql主数据库的root密码
  7. export replication_user="copydb"  #用于复制的mysql用户
  8. export replication_passwd="123456" #mysql用户copydb的密码
  9. export replication_db="centos" #需要同步的数据库名
  10. export master_ip="8.8.8.8"    #mysql主服务器IP
  11.  
  12. #variables for slave
  13. export slave_mysql_root_passwd="123456" #mysql从数据库的root密码
  14. export slave_ip="8.8.4.4"               #从服务器IP地址
  15. export slave_ssh_root_passwd="123456"  #mysql从数据库的ssh的root密码
  16.  
  17. #create replication user
  18. {
  19. ${mysqlbinpath}/mysql -uroot -p${master_mysql_root_passwd} <<EOF
  20. CREATE USER ‘$replication_user’@’$slave_ip’ IDENTIFIED BY ‘$replication_passwd’;
  21. GRANT REPLICATION SLAVE ON *.* TO ‘$replication_user’@’$slave_ip’ IDENTIFIED BY ‘$replication_passwd’;
  22. FLUSH TABLES WITH READ LOCK;
  23. select sleep(10);
  24. EOF
  25. } &
  26.  
  27. #export the database sql data.
  28. ${mysqlbinpath}/mysqldump -uroot -p${master_mysql_root_passwd} ${replication_db} > ${replication_db}.sql
  29.  
  30. #get the master status info.
  31. export status=`${mysqlbinpath}/mysql -uroot -p${master_mysql_root_passwd} -e"show master statusG"`
  32. export binlogname=`echo "$status" | grep "File" | awk ‘{print $2}’`
  33. export position=`echo "$status" | grep "Position" | awk ‘{print $2}’`
  34.  
  35. #create database on slave server.
  36. export createdb="${mysqlbinpath}/mysql -uroot -p${slave_mysql_root_passwd} -e’drop database if exists ${replication_db};create database ${replication_db};’"
  37.  
  38. #import database sql data on slave server.
  39. export importsql="${mysqlbinpath}/mysql -uroot -p${slave_mysql_root_passwd} ${replication_db} < /root/${replication_db}.sql"
  40.  
  41. #deploy the slave mysql server.
  42. export change_master="${mysqlbinpath}/mysql -uroot -p${slave_mysql_root_passwd} -e’stop slave;CHANGE MASTER TO MASTER_HOST="${master_ip}",MASTER_USER="${replication_user}",MASTER_PASSWORD="${replication_passwd}",MASTER_PORT=3306,MASTER_LOG_FILE="${binlogname}",MASTER_LOG_POS=${position},MASTER_CONNECT_RETRY=10;start slave;select sleep(3);show slave statusG’"
  43.  
  44. yum -y install expect
  45. ./slave.exp

expect脚本:slave.exp

  1. #!/usr/bin/expect -f
  2. spawn scp $env(replication_db).sql root@$env(slave_ip):/root
  3. expect {
  4.     "*assword" {set timeout 300; send "$env(slave_ssh_root_passwd)r";}
  5.     "yes/no" {send "yesr"; exp_continue;}
  6.   }
  7. expect eof
  8.  
  9. spawn ssh root@$env(slave_ip) "$env(createdb);$env(importsql);$env(change_master)"
  10. expect {
  11.     "*assword" {set timeout 300; send "$env(slave_ssh_root_passwd)r";}
  12.     "yes/no" {send "yesr"; exp_continue;}
  13.       }
  14. expect eof

使用方法:
上传master.sh和slave.exp两个文件到mysql主服务器,执行master.sh脚本开始配置mysql主从。最后执行完输出的从服务器状态中的 Slave_IO_Running和Slave_SQL_Running都为Yes的话,则说明主从已经配置成功,否则失败。

使用注意:
master.sh文件中的23行有一个select sleep(10)语句,10是指锁表10秒,这个时间根据导出sql数据所需时间定,如果导出sql数据超过10秒,则需要调大锁表时间,否则可能会有用户写入数据而使导致主从配置失败。

监控mysql主从健康状态shell脚本

  1. #!/bin/bash
  2. #define mysql variable
  3. mysql_user="root"
  4. mysql_pass="123456"
  5. email_addr="[email protected]"
  6.  
  7. mysql_status=`netstat -nl | awk ‘NR>2{if ($4 ~ /.*:3306/) {print "Yes";exit 0}}’`
  8. if [ "$mysql_status" == "Yes" ];then
  9.         slave_status=`mysql -u${mysql_user} -p${mysql_pass} -e"show slave statusG" | grep "Running" | awk ‘{if ($2 != "Yes") {print "No";exit 1}}’`
  10.         if [ "$slave_status" == "No" ];then
  11.                 echo "slave is not working!"
  12.                 [ ! -f "/tmp/slave" ] && echo "Slave is not working!" | mail -s "Warn!MySQL Slave is not working" ${email_addr}
  13.                 touch /tmp/slave
  14.         else
  15.                 echo "slave is working."
  16.                 [ -f "/tmp/slave" ] && rm -f /tmp/slave
  17.         fi
  18.         [ -f "/tmp/mysql_down" ] && rm -f /tmp/mysql_down
  19. else
  20.         [ ! -f "/tmp/mysql_down" ] && echo "Mysql Server is down!" | mail -s "Warn!MySQL server is down!" ${email_addr}
  21.         touch /tmp/mysql_down
  22. fi

此脚本首先判断mysql服务器是否运行,如果正常,继续判断主从,否则发邮件告警,只发一次。
判断主从状态是判断IO和SQL线程是否都为yes,如果不是则发邮件通知,只发一次。

shell脚本练习题

这里主要收集一些shell脚本练习题,用于加强shell编程能力。

Q1

分析图片服务日志,把日志(每个图片访问次数*图片大小的总和)排行,也就是计算每个url的总访问大小
说明:本题生产环境应用:这个功能可以用于IDC网站流量带宽很高,然后通过分析服务器日志哪些元素占用流量过大,进而进行优化或裁剪该图片,压缩js等措施。
测试数据
59.33.26.105 – – [08/Dec/2010:15:43:56 +0800] “GET /static/images/photos/2.jpg HTTP/1.1” 200 11299
本题需要输出三个指标: 【被访问次数】 【访问次数*单个被访问文件大小】 【文件名(带URL)】
查看答案

Q2

计算出1+2+3+..+100的结果。可以使用多种方法解答。
查看答案

Q3

分析网站日志,找出在一分钟内打开网页超过60次的ip(排除图片,js和css等静态元素),并用iptables禁止其访问。加入crontab使脚本每分钟执行一次。
查看答案

Q4

teamlist.txt的内容为:

  1. Name,Team,First Test, Second Test, Third Test
  2. Tom,Red,5,17,22
  3. Joe,Green,3,14,22
  4. Maria,Blue,6,18,21
  5. Fred,Blue,2,15,23
  6. Carlos,Red,-1,15,24
  7. Phuong,Green,7,19,21
  8. Enrique,Green,3,16,20
  9. Nancy,Red,9,12,24

编写一个awk脚本用来计算每个人的平均成绩,每次测试的平均成绩和每组队的平均成绩。如果某次成绩为负数,则表示此人错过了测试,那计算平均成绩时排除此人再计算。
输出的结果如下表,在名字的列表中,名字是10个宽度且左对齐(提示printf中使用%-10s格式),而平均值是7个字符宽度,右边两个右对齐的小数。

  1. Name       Average
  2. —-       ——-
  3. Tom          14.67
  4. Joe          13.00
  5. Maria        15.00
  6. Fred         13.33
  7. Carlos       19.50
  8. Phuong       15.67
  9. Enrique      13.00
  10. Nancy        15.00
  11. ——————
  12. Average for Test 1 : 5
  13. Average for Test 2 : 15.75
  14. Average for Test 3 : 22.125
  15. ——————-
  16. Average for Red Team: 16
  17. Average for Blue Team: 14.1667
  18. Average for Green Team: 13.8889

查看答案

Q5

传入至少三个数字参数到脚本file,并计算出最大,最小,平均值。需要判断传入的数字是否足够,否则输出警告信息。平均值保留两位小数。
如执行./file 3 4 6 5,输出结果如下:
max number is:6
min number is:3
average is:4.50
查看答案

Q6

有一列数字如下:
第1次:1
第2次:2
第3次:3
第4次:5
第5次:8
第6次:13
第7次:21
第8次:34
第9次:55
第10次:89
第11次:144
写出100次的数是什么。
查看答案

Q7

文件内容如下:
123abc456
456def123
567abc789
789def567
要求输出:
456ABC123
123DEF456
789ABC567
567DEF789
查看答案

shell脚本练习题答案

Q1答案

  1. awk ‘{url[$7]++;size[$7]+=$10}END{for (a in url) {print size[a]/1024"K",url[a],a}}’ access.log

解析:
这里定义了两个数组url和size,数组url用来计算单个url被访问的次数,数组size则是统计单个url传输的总字节数。之后的for语句则是循环读取数组url的无素,即链接,然后相继打印出单个url传输总字节数,被访问次数及相应的链接。
数据分析出来后,我们可以使用sort命令进行排序。

Q2答案

方法1:for…do…done 的数值处理

  1. sum=0
  2. for ((i=1;i<=100;i++))
  3. do
  4. ((sum+=$i))
  5. done

方法2:for…do…done (固定回圈)

  1. sum=0
  2. for i in {1..100}
  3. do
  4. ((sum+=$i))
  5. done

方法3:while do done (不定回圈)

  1. sum=0
  2. i=1
  3. while [[ $i -le 100 ]]
  4. do
  5. ((sum+=i))
  6. ((i++))
  7. done

方法4:until do done (不定回圈)

  1. sum=0
  2. i=1
  3. until [[ $i -gt 100 ]]
  4. do
  5. ((sum+=i))
  6. ((i++))
  7. done

方法5:构建1+2+3..再利用bc计算

  1. seq 100 | tr "n" "+" | sed ‘s/+$/n/’ | bc

Q3答案

  1. now=`date +%H%M%S`
  2. ago=`date -d "1 minute ago" +%H%M%S`
  3. badip=`tail -n 10000 access.log | egrep -v ".(gif|jpg|jpeg|png|css|js)" | awk  ‘
  4. BEGIN{
  5. n=’"$now"’
  6. a=’"$ago"’
  7. FS="[ :]+"
  8. }
  9. {
  10. t=$5$6$7
  11. if (t>=a && t<=n) {
  12. num[$1]++
  13. }
  14. }
  15. END{
  16. for (ip in num){
  17. if (num[ip]>60){
  18. print ip
  19. }
  20. }
  21. }
  22. ‘`
  23. if [ ! -z "$badip" ];then
  24. for ip in $badip;
  25. do
  26. if test -z "`/sbin/iptables -nL | grep $ip`";then
  27. /sbin/iptables -I INPUT -s $ip -j DROP
  28. fi
  29. done
  30. fi

解析:
1、定义两个变量now和ago,分别为当前时间,一分钟前的时间,格式为%H%M%S。
2、获取日志最后的一万行(可以根据自己的访问量修改),使用egrep排除图片等文件。
3、在awk的BEGIN语句中调用第1步设置的两个变量。
4、使用变量t,a,n判断并获取一分钟内的日志,并使用数组num统计ip出现的次数。
5、在END语句中判断ip出现的次数是否超过60,如果超过则输出ip地址到变量badip。
6、for循环获取变量badip中的每个ip,并加入iptables规则禁止访问。

Q4答案

  1. awk -F, ‘BEGIN{
  2. printf "%-10s %sn","Name","Average"
  3. printf "%-10s %sn","—-","——-"
  4. }
  5. NR>1{
  6. sum=0
  7. n=0
  8. for (i=3;i<=5;i++){
  9. if ($i>0){
  10. n++
  11. sum=sum+$i
  12. testcount[i-2]++
  13. testtotal[i-2]+=$i
  14. teamcount[$2]++
  15. teamtotal[$2]+=$i
  16. }
  17. }
  18. printf "%-10s %7.2fn",$1,sum/n
  19. }
  20. END{
  21. print "——————"
  22. for (j=1;j<=3;j++){
  23. print "Average for Test "j" : "testtotal[j]/testcount[j]
  24. }
  25. print "——————-"
  26. for (t in teamcount){
  27. print "Average for "t" Team: "teamtotal[t]/teamcount[t]
  28. }
  29. }’  teamlist.txt

解析:
1、awk的BEGIN语句输出表的两个列名。
2、NR>1表示只处理从第二行开始的数据
3、sum=0,n=0,初始化三个测试总成绩和参加的次数。
4、定义一个for循环,循环处理三次测试数据。
5、判断成绩大于0才处理此次测试。
6、为计算每个人的平均成绩,用变量n记录测试次数,变量sum累积三次的成绩,接着下面用printf格式化输出每个人的平均成绩;为计算三个测试中每次的平均成绩,以i-2作为索引(即第i-2次测试),数组testcount记录某次测试参加的人数,数组testtotal记录某次测试的总成绩;为计算每个组的平均成绩,以第二列组名作为索引,数组teamcount记录某组参加测试的人数,数组teamtotal记录某组的总成绩。
7、在END语句中用两个for循环语句分别输出每次测试及每组测试的平均成绩。

Q5答案

方法一:利用awk命令计算

  1. if [ "$#" -lt 2 ];then
  2. echo "parameter must be at least 3."
  3. exit 1
  4. fi
  5. echo "$@" | awk ‘
  6. BEGIN{
  7. RS=" +"
  8. }
  9. {
  10. sum+=$0
  11. }
  12. NR==1 {
  13. max=$1;min=$1
  14. next
  15. }
  16. $1>max {
  17. max=$1
  18. }
  19. $1<min {
  20. min=$1
  21. }
  22. END{
  23. printf "max number is:%sn",max
  24. printf "min number is:%sn",min
  25. printf "average is:%.2fn",sum/NR
  26. }’

解析:
1、判断参数是否大于2个,否则退出脚本。
2、管道传入所有参数到awk,并设置awk的RS为空格。
3、sum+=$0,计算和。
4、NR==1 {}把第一个参数先赋值到max和min,防止所有数字为负数时计算错误。
5、$1>max{}判断数字是否比变量max目前的数大,如果是,则把$1赋值到max,这样变量就可以时刻保持最大值状态。
6、$1<min{}同上原理。
7、最大打印出最大,最小值,平均则是sum/NR。
方法2:使用while,shift等命令

  1. n=$#
  2. if [ "$n" -lt 2 ];then
  3. echo "parameter must be at least 3."
  4. exit 1
  5. fi
  6. max=$1
  7. min=$1
  8. sum=$1
  9. shift
  10. while [ $# -gt 0 ]
  11. do
  12. ((sum+=$1))
  13. [ $1 -gt $max ] && max=$1
  14. [ $1 -lt $min ] && min=$1
  15. shift
  16. done
  17. echo "max number is:"$max
  18. echo "min number is:"$min
  19. ave=`echo "scale=2;$sum / $n" | bc`
  20. echo "average is:"$ave

解析:
1、把参数个数赋值到变量n
2、判断参数个数
3、把第一个数字赋值到max,min,sum变量,并用shift命令使参数向左移,即之前的$2变为$1,且变量$#减1。
4、while结合shift命令依次读取各参数,并在里面判断最大最小值。
5、echo输出最大最小值,bc计算平均值,定义scale=2以保留两位小数。

Q6答案

  1. a[1]=1
  2. a[2]=2
  3. i=3
  4. while [ $i -le 100 ]
  5. do
  6. ((a[$i]=${a[$i-1]}+${a[$i-2]}))
  7. ((i++))
  8. done
  9. echo ${a[100]}

Q7答案

  1. sed  ‘s/([0-9]*)([a-z]*)([0-9]*)/3U2E1/’ file

解析:
1、([0-9]*)匹配连续的数字,([a-z]*)匹配连续的小写字母。
2、123表示引用之前的括号内容,U2E表示把2的字母转换为大写字母。