shell脚本练习题,shell练习题Q1分析图片服务日志


这里主要收集一些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的内容为:

Name,Team,First Test, Second Test, Third Test

Tom,Red,5,17,22

Joe,Green,3,14,22

Maria,Blue,6,18,21

Fred,Blue,2,15,23

Carlos,Red,-1,15,24

Phuong,Green,7,19,21

Enrique,Green,3,16,20

Nancy,Red,9,12,24

编写一个awk脚本用来计算每个人的平均成绩,每次测试的平均成绩和每组队的平均成绩。如果某次成绩为负数,则表示此人错过了测试,那计算平均成绩时排除此人再计算。


输出的结果如下表,在名字的列表中,名字是10个宽度且左对齐(提示printf中使用%-10s格式),而平均值是7个字符宽度,右边两个右对齐的小数。

Name Average

---- -------

Tom 14.67

Joe 13.00

Maria 15.00

Fred 13.33

Carlos 19.50

Phuong 15.67

Enrique 13.00

Nancy 15.00

------------------

Average for Test 1 : 5

Average for Test 2 : 15.75

Average for Test 3 : 22.125

-------------------

Average for Red Team: 16

Average for Blue Team: 14.1667

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


全部答案如下:


Q1答案

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 的数值处理

sum=0

for ((i=1;i<=100;i++))

do

((sum+=$i))

done

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

sum=0

for i in {1..100}

do

((sum+=$i))

done

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

sum=0

i=1

while [[ $i -le 100 ]]

do

((sum+=i))

((i++))

done

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

sum=0

i=1

until [[ $i -gt 100 ]]

do

((sum+=i))

((i++))

done

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

seq 100 | tr "n" "+" | sed 's/+$/n/' | bc

Q3答案

now=`date +%H%M%S`

ago=`date -d "1 minute ago" +%H%M%S`

badip=`tail -n 10000 access.log | egrep -v ".(gif|jpg|jpeg|png|css|js)" | awk '

BEGIN{

n='"$now"'

a='"$ago"'

FS="[ :]+"

}

{

t=$5$6$7

if (t>=a && t<=n) {

num[$1]++

}

}

END{

for (ip in num){

if (num[ip]>60){

print ip

}

}

}

'`

if [ ! -z "$badip" ];then

for ip in $badip;

do

if test -z "`/sbin/iptables -nL | grep $ip`";then

/sbin/iptables -I INPUT -s $ip -j DROP

fi

done

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答案

awk -F, 'BEGIN{

printf "%-10s %sn","Name","Average"

printf "%-10s %sn","----","-------"

}

NR>1{

sum=0

n=0

for (i=3;i<=5;i++){

if ($i>0){

n++

sum=sum+$i

testcount[i-2]++

testtotal[i-2]+=$i

teamcount[$2]++

teamtotal[$2]+=$i

}

}

printf "%-10s %7.2fn",$1,sum/n

}

END{

print "------------------"

for (j=1;j<=3;j++){

print "Average for Test "j" : "testtotal[j]/testcount[j]

}

print "-------------------"

for (t in teamcount){

print "Average for "t" Team: "teamtotal[t]/teamcount[t]

}

}' 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命令计算

if [ "$#" -lt 2 ];then

echo "parameter must be at least 3."

exit 1

fi

echo "$@" | awk '

BEGIN{

RS=" +"

}

{

sum+=$0

}

NR==1 {

max=$1;min=$1

next

}

$1>max {

max=$1

}

$1<min {

min=$1

}

END{

printf "max number is:%sn",max

printf "min number is:%sn",min

printf "average is:%.2fn",sum/NR

}'

解析:


1、判断参数是否大于2个,否则退出脚本。


2、管道传入所有参数到awk,并设置awk的RS为空格。


3、sum+=$0,计算和。


4、NR==1 {}把第一个参数先赋值到max和min,防止所有数字为负数时计算错误。


5、$1>max{}判断数字是否比变量max目前的数大,如果是,则把$1赋值到max,这样变量就可以时刻保持最大值状态。


6、$1


7、最大打印出最大,最小值,平均则是sum/NR。


方法2:使用while,shift等命令


n=$#

if [ "$n" -lt 2 ];then

echo "parameter must be at least 3."

exit 1

fi

max=$1

min=$1

sum=$1

shift

while [ $# -gt 0 ]

do

((sum+=$1))

[ $1 -gt $max ] && max=$1

[ $1 -lt $min ] && min=$1

shift

done

echo "max number is:"$max

echo "min number is:"$min

ave=`echo "scale=2;$sum / $n" | bc`

echo "average is:"$ave

解析:


1、把参数个数赋值到变量n


2、判断参数个数


3、把第一个数字赋值到max,min,sum变量,并用shift命令使参数向左移,即之前的$2变为$1,且变量$#减1。


4、while结合shift命令依次读取各参数,并在里面判断最大最小值。


5、echo输出最大最小值,bc计算平均值,定义scale=2以保留两位小数。


Q6答案

a[1]=1

a[2]=2

i=3

while [ $i -le 100 ]

do

((a[$i]=${a[$i-1]}+${a[$i-2]}))

((i++))

done

echo ${a[100]}

Q7答案

sed 's/([0-9]*)([a-z]*)([0-9]*)/3U2E1/' file

解析:


1、([0-9]*)匹配连续的数字,([a-z]*)匹配连续的小写字母。


2、123表示引用之前的括号内容,U2E表示把2的字母转换为大写字母。

相关内容

    暂无相关文章