首页 > 系统服务 > 详细

shell 练习题集合(思路和解答)

时间:2016-02-03 06:43:50      阅读:414      评论:0      收藏:0      [点我收藏+]

##########################################################################################

https://www.centos.bz/2012/07/shell-script-exercises/

Q1:

Q1题目:

分析图片服务日志,把日志(每个图片访问次数*图片大小的总和)排行,也就是计算每个url的总访问大小明:本题生产环境应用:这个功能可以用于IDC网站流量带宽很高,然后通过分析服务器日志哪些元素占用流量过大,进而进行优化或裁剪该图片,压缩js等措施。


测试数据 access_log

59.33.26.105 – – [08/Dec/2010:15:43:56 +0800] “GET /static/images/photos/2.jpg HTTP/1.1″ 200 11299


输入要求:

本题需要输出三个指标: 【被访问次数】 【访问次数*单个被访问文件大小】 【文件名(带URL)】


Q1知识回顾:awk

awk 语法: [-F  field-separator]  ‘{pattern + action}‘  input-file(s)

awk 把文件逐行读入,默认域分隔符是"空白键" 或 "tab 键",可以用 -F ‘ ‘ 修改;$0则表示所有域,$1表示第一个域,$n表示第n个域。


常见例子:

awk -F: ‘BEGIN {count=0;print "[start] user count is:",count} {count=count+1;print $1;} END {print "[end]user count is:" count}‘ /etc/passwd

[start]user count is  0

root

...

[end]user count is  40


!!重要技巧

因为awk是以字符串格式来存储数字值,但又可以进行数值计算;

并且数组中的下标也同样视为字符串array["1"]=array[1]。特别的,还可以用字符串来作为下标,myarr["name"]="Mr. Whipple",print myarr["name"] 正常。这种数组叫做关联数组。


Q1思路:

分析http日志,用awk命令

access_log中的第七列为访问的文件(路径),第十列为返回数据大小即图片大小B.(补充:第九列为状态码)


Q1解答:

awk ‘BEGIN{} {url[$7]++;size[$7]+=$10;} END{for (a in url) {print url[a],size[a]/1024 "K",a}}‘ /var/log/httpd/access_log

url记录单个url被访问次数,size统计总字节。

##########################################################################################

Q2:

Q2问题;

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


Q2知识回顾:

shell中的数学运算不同于$变量,

如:var=1+1 echo $var 输出的结果是1+1;

如:var=1 var=$var+1 echo $var 输出结果是1+1

数组运算不需要带$


整数运算:let,(()),$[],expr

浮点数运算:管道方法bc,awk,


for语法:for (()) do done


Q2解答1:

在有bc命令下:seq -s “+” 100 | bc 


Q2解答2:

sum=0

for ((i=0;i<=100;i++)) 或者 for i in {1..100}

do

((sum+=i))

done

echo $sum


Q2解答3:

sum=0

i=0

while [ i -le 100 ]

do

((sum+=i))

done

echo $sum

##########################################################################################

Q3:

Q3题目:

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


Q3知识回顾:

egrep = grep -E 可以使用基本的正则表达外, 还可以用扩展表达式. 注意区别.扩展表达式:

egrep 用以下的字符的特殊功能(如果需要匹配一下字符,可以“\”转义

+ 匹配一个或者多个先前的字符, 至少一个先前字符.

? 匹配0个或者多个先前字符.

a|b|c 匹配a或b或c

() 字符组, 如: love(able|ers) 匹配loveable或lovers.

(..)(..)\1\2 模板匹配. \1代表前面第一个模板, \2代第二个括弧里面的模板.

x{m,n} =x\{m,n\} x的字符数量在m到n个之间.


Q3思路:

用当前时间的前后一分钟来分析 date +%H%M%S 和 date -d "1 minute ago" +%H%M%S

日志记录的时间在一分钟的范围内,ip_count[$1]++

用egrep -v .(gif|jpg|jpeg|png|css|js) 排除

awk 命令 -F "[ :]" 提取出%H%M%S,这里有比较特殊的是IPV6地址::1,得再筛选掉。

另外注意的是:在加入iptables是要加判断

Q3解答:

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

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

badip=`tail -n 10000 /var/log/httpd/access_log |egrep -v "^::" |egrep -v ".(gif|jpg|jpeg|png|css|js)" | awk -F "[ :]" ‘BEGIN{

n=‘"$now"‘;

a=‘"$a_min_ago"‘;

}

{

t=$5$6$7;

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

ip_count[$1]++;

}


END{

for (ip in ip_count){

if (ip_count[ip]>10){

print ip;

}

}

}

‘`

echo $badip

if [ ! -z $badip ];

then

for ip in $badip

do

if [ -z "`/sbin/iptables -nL |grep $ip`" ];

then

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

fi

done

fi

##########################################################################################

Q4:

Q4题目:

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


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



Q4答案:

#!/bin/bash

awk -F "," ‘BEGIN{

printf "%-10s %s\n","Name","Average";

printf "%-10s %s\n","----","-------";

}

NR>1{

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

if ($i>0){

name_count[$1]++;

name_sum[$1]+=$i;

test_count[i-2]++

test_sum[i-2]+=$i

team_count[$2]++;

team_sum[$2]+=$i;

}

}

printf "%-10s %7.2f\n",$1,name_sum[$1]/name_count[$1];

}

END{

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

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

print "Average for Test "j": " test_sum[j]/test_count[j]

}

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

for (t in team_count){

print "Average for "t" Team: " team_sum[t]/team_count[t];

}

}‘ teamlist

##########################################################################################

Q5:

Q5题目:

传入至少三个数字参数到脚本file,并计算出最大,最小,平均值。需要判断传入的数字是否足够,否则输出警告信息。平均值保留两位小数。


Q5答案:

#!/bin/bash

n=$#

if [ $n -lt 3 ];then

echo "parameter must be at least 3"

exit 1

fi

max=$1

min=$1

sum=$1

shift

while [ $# -gt 0 ]

do

((sum+=$1))

if [ $1 -gt $max ];then

max=$1

fi

if [ $1 -lt $min ];then

min=$1

fi

shift

done

echo "max number is: " $max

echo "min number is: " $min

ave=`echo "$sum $n" |awk ‘{printf("%.2f", $1/$2)}‘`

echo "ave number is: " $ave

##########################################################################################

Q6:

Q6题目:

有一列数字如下:

第1次:1

第2次:2

第3次:3

第4次:5

第5次:8

第6次:13

第7次:21

第8次:34

第9次:55

第10次:89

第11次:144

写出100次的数是什么。


Q6答案:


给的参考答案在92的时候出现复数。

自己的答案:

#!/bin/bash

awk ‘BEGIN{

num[1]=1;

num[2]=2;

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

num[i]=num[i-1]+num[i-2]

}

print num[‘"$1"‘]

}‘

##########################################################################################

Q7:

Q7题目:

文件内容如下:

123abc456

456def123

567abc789

789def567

要求输出:

456ABC123

123DEF456

789ABC567

567DEF789


Q7答案:

自己的答案;

#!/bin/bash

awk ‘{

a=substr($1,1,3);

b=toupper(substr($1,4,3));

c=substr($1,7,3);

printf c

printf b

printf a

printf "\n"

}‘ q7data

##########################################################################################

Q8:

Q8问题:

1 2 4 8

5 8 0 2

3 1 8 3

7 0 2 7

3 9 1 0

3 2 7 4

把第2列和第3列的和作为新的第5列,第5列的平均值为avg5,求第5列中大于avg5的行数。


Q8答案:

a=`cat data |wc -l`

awk ‘BEGIN{

i=1;

j=1;

count=0;

count2=0;

}

{

x=$2+$3

num[i]=x

i++

sum+=x

print NR

}

END{

avg5=sum/‘"$a"‘

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

if (num[j]>avg5){

count++

}

}

for (k in num){

if (num[k]>avg5){

count2++;

}


}

print "The sum: " sum

print "The average: " avg5

print "The counter: " count

print "The counter2: " count2

}‘ data

##########################################################################################

Q9:

Q9问题:

stu.txt

100:张三:男:计算机  

101:张红:女:文秘  

102:张飞:男:体育  

103:张婷:女:英语  

104:张海洋:男:机电  


该文件是所有学生的信息,每个学生存储一行信息,信息格式如下:学号:姓名:性别:专业    如(100:张三:男:计算机)设计一个shell,名称为stu.sh,该shell完成如下功能:

1)当输入stu.sh时,列出所有记录内容

2)当输入 stu.sh -a 100:张三:男:计算机    时,首先判断100记录是否存在,如果不存在,则把该信息写入文件,如果存在,则给出提示,并输出文件中学号为100的该行信息

3)当输入 stu.sh -d 100时,首先判断100记录是否存在,如果不存在,给出提示,如果存在,则提示用户确认是否要删除记录,如用户输入y或者yes,则删除文件中学号为100的该行信息,如果用户输入n或no时,则不做删除操作

4)当输入 stu.sh -s 100时,首先判断100记录是否存在,如果不存在,给出提示,如果存在,则输出文件中学号为100的该行信息

5)当用户输入的选项不正确时,给出错误提示,并输入该shell的用法

Q9答案:

data="stu.txt";

sid="学号";

sname="姓名";

ssex="性别";

smajor="专业";


help(){

 echo "不加参数,显示所有记录";

 echo "-a 添加记录";

 echo "-d 删除记录";

 echo "-s 搜索记录";

}


if [ $# -eq 0  ];

then

 printf "%-s\t%-s\t%-s\t%-s\n" $sid $sname $ssex $smajor;

 #cat $data |awk -F ":" ‘{printf("%-s\t%-s\t%-s\t%-s\n",$1,$2,$3,$4);}‘;二选一

 cat $data|tr ‘:‘ ‘\t‘;

 exit;

fi


case $1 in 

-a)

 if ! grep -q $2 $data 2>&1;

 then

       echo $2>>$data;

       exit;

 else

       echo "存在";

       printf "%-s\t%-s\t%-s\t%-s\n" $sid $sname $ssex $smajor;

       echo $2|tr ‘:‘ ‘\t‘;

 fi

;;

-d)

 if ! grep -q $2 $data 2>&1;

 then

       echo "记录不存在。。";

       exit;

 else

       read -p "确定要删除?(y/n)" confirm;

       if [ $confirm == "y" -o $confirm == "yes" ];

       then

               sed -i "/$2/d" $data 2>&1;

       elif [ $confirm == "n" -o $confirm == "no" ];

       then

               echo "用户取消";

       else

               echo "错误的输入";

       fi

 fi

;;

-s)

 if ! grep -q $2 $data 2>&1;

 then

       echo "记录不存在。。";

       exit;

 else

       printf "%-s\t%-s\t%-s\t%-s\n" $sid $sname $ssex $smajor;

       #sed -n "/$2/p" $data |tr ‘:‘ ‘\t‘;

       grep $2 $data|tr ‘:‘ ‘\t‘;

 fi

;;

*)

 help

;;

esac

##########################################################################################

Q10:

Q10问题:

vat 1.txt

1 aa

2 bb

3 ee

4 ss


cat 2.txt

1 ab

2 cd

3 ad

4 bd

5 de


合并后的结果为:

1 ab aa

2 cd bb

3 ad ee

4 bd ss

5 de


Q10思路:

处理单个文件时,NR=FNR

处理多个文件时,按顺序处理。NR的行数会继续+,而FNR重新从1开始


Q10解答:

awk ‘NR==FNR{a[$1]=$2}NR>FNR{print $0,a[$1]}‘  1.txt  2.txt

等同于:

awk ‘BEGIN{

}

{

if (NR==FNR){

a[$1]=$2

if (NR>FNR){

print $0,a[$1]

}

}

END{

}’ 1.txt 2.txt

##########################################################################################

Q11:

Q11题目:

编写shell脚本,将/usr/local/test目录下大于100k的文件转移到/tmp目录下。


Qxx答案:

#!/bin/bash

for file in `ls /home/linpeisong`

do

if [ -f /home/linpeisong/$file ];then

echo /home/linpeisong/$file

if [ `ls -l  /home/linpeisong/$file |awk ‘{print $5}‘` -gt 100000 ];then

cp /home/linpeisong/$file /tmp/

fi

fi

done


##########################################################################################

Q12:

Q12问题:

统计英语作文中单词频率,按单词,次数,降序排序


Q12思路:

用awk,gsub去掉符号,数组统计i


Q12答案:

#!/bin/bash

awk ‘BEGIN{

}

{

# NF表示浏览记录域的个数

gsub(/[.=,:;!?(){}]/, "")  

for(i=1;i<=NF;i++){

count[$i]++

}

}

END{

for(word in count){

print word,count[word] | "sort -nr -k 2"

}

}‘ file.txt


##########################################################################################

Q13:

shell计时,毫秒

START=`date +%s%N`

END=`date +%s%N`

time=`expr $((END-START)) / 1000000

echo $time"ms"


来自LeetCode的几道题目

##########################################################################################

Q14: Valid Phone Numbers


Given a text file file.txt that contains list of phone numbers (one per line), write a one liner bash script to print all valid phone numbers.


You may assume that a valid phone number must appear in one of the following two formats: (xxx) xxx-xxxx or xxx-xxx-xxxx. (x means a digit)


You may also assume each line in the text file must not contain leading or trailing white spaces.


For example, assume that file.txt has the following content:


987-123-4567

123 456 7890

(123) 456-7890

Your script should output the following valid phone numbers:

987-123-4567

(123) 456-7890


Q14思路:用sed,grep,awk匹配即可


Q14答案:(16ms)

awk "/^([0-9]{3}-)[0-9]{3}-[0-9]{4}$|^(\([0-9]{3}\)) [0-9]{3}-[0-9]{4}$/" file.txt


##########################################################################################

Q15: Tenth Line


How would you print just the 10th line of a file?


For example, assume that file.txt has the following content:


Line 1

Line 2

Line 3

Line 4

Line 5

Line 6

Line 7

Line 8

Line 9

Line 10

Your script should output the tenth line, which is:

Line 10


Q15思路:可以用head匹配第十行(不过得先做判断);或者用awk直接匹配


Q15解答1: (12ms)

#!/bin/bash

line_number=$(cat file.txt |wc -l)

if [ $line_number -lt 10 ];then

echo ""

else 

head -n 10 file.txt |tail -n 1

fi


Q15解答2: (16ms)

awk ‘NR==10‘ file.txt


##########################################################################################

Q16: Word Frequency


Write a bash script to calculate the frequency of each word in a text file words.txt.


For simplicity sake, you may assume:


words.txt contains only lowercase characters and space ‘ ‘ characters.

Each word must consist of lowercase characters only.

Words are separated by one or more whitespace characters.

For example, assume that words.txt has the following content:


the day is sunny the the

the sunny is is

Your script should output the following, sorted by descending frequency:

the 4

is 3

sunny 2

day 1


Q16思路:可以利用shell中的关联数组保存词和对应词的次数,awk编程


Q16解答:(8ms)

#!/bin/bash

awk ‘BEGIN{

}

{

for(i=1;i<=NF;i++){

count[$i]++

}

}

END{

for(word in count){

print word,count[word] | "sort -nr -k 2"

}

}‘ words.txt


##########################################################################################

Q16: Transpose File


Given a text file file.txt, transpose its content.


You may assume that each row has the same number of columns and each field is separated by the ‘ ‘ character.


For example, if file.txt has the following content:


name age

alice 21

ryan 30

Output the following:


name alice ryan

age 21 30


Q16思路:awk,数组


Q16解答:(40ms)

#!/bin/bash
awk ‘{
for(i=1;i<=NF;i++){
a[NR,i]=$i
}
}
END{
for(i=1;i<=NF;i++){
for(j=1;j<=NR;j++){
if(j==NR){
printf a[j,i]"\n"
}
else{
printf a[j,i]" "
}
}
}
}‘ file.txt


本文出自 “新手PS欢迎交流” 博客,请务必保留此出处http://linpeisong.blog.51cto.com/9601554/1740790

shell 练习题集合(思路和解答)

原文:http://linpeisong.blog.51cto.com/9601554/1740790

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!