##########################################################################################
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
原文:http://linpeisong.blog.51cto.com/9601554/1740790