本文转自敬爱的林肯老师博客


一 文件内容如下:
100
a         100
b         -50
c         -20
d         -30
要求输出结果为:
100
a          100
200
b          -50
150
c           -20
130
d          -30
 
一句话思路:用shell肯定是不行,因为是操作文件。用sed倒是可以操作文件,但有数学运算还要用到变量。所以,用awk应该是最好的。
awk     'NR==1{sum=$1;print $0}NR!=1{print $0;sum=sum-$2;print sum}'     内容文件
知识点:awk变量,域
 
二 文件内容如下:
123abc456
456def123
567abc789
789def567
要求输出:
456ABC123
123DEF456
789ABC567
567DEF789
 
一句话思路:以点带面,文字处理,shell不行,awk不行,用sed加正则表达式
sed -r  's/([1-9]{3})([a-f]{3})([1-9]{3})/\3\2\1/;y/abcdef/ABCDEF/'  内容文件
知识点:-r 支持扩展的正则表达式,跟grep用-P类似。y其实就是tr只是写到sed里面更好看一些,sed的查找替换,当然还有正则中的分组。sed中的分组可以这么用,awk就不行了只能用&,而且分组数量不能超过9,即不会有\10出现。
 
三. 文件内容如下
1.1.1.1      11
1.1.1.1      22
1.1.1.1      33
1.1.1.1      44
2.2.2.2      11
2.2.2.2      22
2.2.2.2      33
2.2.2.2      44
要求使用sed及awk分别将文件输出:
1.1.1.1       11  22  33  44
2.2.2.2       11  22  33  44
 
一句话思路:这个没啥思路了,上面还分析分析用什么合适,这里面没的选了,人家都说了,就弄吧。
sed   -r   'N;N;N;s/\n/ /g;s/(.*)(11 )(.*)(22 )(.*)(33 )(.*)(44)/\1\2\4\6\8/'   内容文件
知识点:N将文件的下一行读入模式空间,3个N就是读取下面三行进入当前模式空间,读进去的行依然保留换行,所以删除换行,后面的就不说了,你懂的。
awk    '{sum[$1]=sum[$1]" "$2}END{for(var in sum)print var sum[var]}'  内容文件
知识点:awk数组,awk字符串赋值,使用for遍历awk数组。
 
四. 分析apache日志,给出当日访问ip的降序列表。
一句话思路:分析ip就要提取ip,提取的办法除了awk,还有个东西叫cut。
cut  -d " "   -f1   /etc/httpd/log/access_log  |  sort  |  uniq  -c  |  sort  -nr
知识点:cut命令,sort将汇总相同内容,uniq -c合并重复内容,并给出重复次数。sort  -nr  使用数字排序,默认是ascii,并且是降序,默认是升序。
awk      '{sum[ip]++}END{for(var in sum)print ip sum[var]}'   /etc/httpd/log/access_log  | sort -k2 -nr
知识点:awk数据,sort -k2 -nr 降序数字排序就不说了,-k参数指定使用哪个列进行排序。默认是自然是第一列。
 
五.亚瑟王环
有1到100的数字序列。有计数器每数到12,就将计数器指向的数字在亚瑟环中剔除,问该序列中最后剩下的数字是多少?
一句话思路:100,12的太复杂,就弄个10,2的,完成之后替换一下。。。。。。
最后的答案是:81    面试的时候你可以说是心算的(别脱口而出,稍微伪装一下),就是不知道行不行。
做计数器,当计数器到达12的时候就将一个数组中对应的值赋值为零。当所有数组中的数字还剩唯一的不为零的值的时候就是剩下的数字。
#/bin/bash
for   i   in   {1..100};do
huan[$i]=$i
done      #先初始化一个数组,其实用变量也行,个人喜好,用awk也行,但一篇内容一个shell有点不合适。
t=0  #定义一个计数器
sum=0
while true;do   #定义一个无限循环,因为确实不知道要数多少次。
    for((i=1;i<101;i++));do
        if [ ${huan[$i]} -gt 0 ];then  #不等于零就把计数器加1
            let t++
        fi
        if [ $t -eq 12 ];then  #数到12就将数组中的数清零,同时计数器清零
            huan[$i]=0
            t=0
        fi
    done
    for((i=1;i<101;i++));do  #遍历数组,如果数组中只有一个数不为零就跳出循环
        if [ ${huan[$i]} -gt 0 ];then
            let sum++
            sum[1]=${huan[$i]}
        fi
    done
    if [ $sum -eq 1 ];then
        break
    else 
        sum=0
    fi
done
         echo ${sum[1]}
篇幅有限,不能全部列出,后面还会不断有内容更新。欢迎批评指教,不详之处,务请见谅!
 
 
 
 
本文出自 “ 林肯” 博客,请务必保留此出处 http://president.blog.51cto.com/4990508/851407



  这篇的内容相对基础,主要集中在计划任务和find命令上面。
       crontab 分时日月周 find命令的 exec 和 xargs 这是两个比较容易遗忘的知识点。

1、编写shell程序,实现自动删除50个账号的功能。账号名为stud1至stud50。
     一句话思路:找出规律,循环解决
     for((i=1;i<51;i++));do userdel -r stud$i ;done
     知识点:for循环,当然是用while循环也是可以的,until也行。
  
2、某系统管理员需每天做一定的重复工作,请按照下列要求,编制一个解决方案:
(1)在下午4 :50删除/abc目录下的全部子目录和全部文件;
(2)从早8:00~下午6:00每小时读取/xyz目录下x1文件中每行第一个域的全部数据加入到/backup目录下的bak01.txt文件内;
(3)每逢星期一下午5:50将/data目录下的所有目录和文件归档并压缩为文件:backup.tar.gz;
  
    一句话思路:主要考验管理员对于计划任务的熟悉程度
     crontab -e
     50 16 * * * rm -rf /abc/*
     * 8-18/1 * * * awk '{print $1 > "/backup/bak01.txt"}' /xyz/x1
     50 17 * * 1 tar -czf backup.tar.gz /data
  
    知识点:awk的输出重定向,当然用管道也是可以的。tar命令打包参数,这样做会有一个提示,只是去掉了目录不用理会。

  3、gameser这个服务启动命令为./gameser服务,请写一个脚本,当服务宕掉,脚本自动拉起gameser服务。
  
    一句话思路:进程管理
  
#!/bin/bash

while true;do

        result=`ps aux | grep gameser | wc -l`
  
        if [ $result -lt 2 ];then  ./gameser; fi
  
        sleep 5
done
  
知识点:还可以使用pgrep命令。
  
4、linux crontab;请在3月23号21点18分的时候,重启服务器
  
    一句话思路:计划任务+关机
  
    crontab -e
    18 21 23 3 * init 6
  
    知识点:可能会延展提问到最安全的关机命令,“写缓存”sync 最好两遍,有人说三遍,其实四遍也行,要不干脆还是别关机了!
  
5、你想每天23:00运行xxxx.sh脚本。并自动进行日志分析。第2天上班的时候看到分析结果 给出你的部属方案
  
    一句话思路:计划任务,日志分析
  
    0 23 * * * sh ****.sh;err=$?;logger -p cron.err $err
  
    知识点:第一个参数一定要写零,否则在定义的23点里每分钟都会执行。计划任务只有当报错的时候才会以邮件形式发送给用户,所以这里使用logger命令将消息发送给日志服务器,这里只是发送了命令返回值,你可以随意发送内容,看你喜欢了。
  
6、要求:运行脚本输入两个数得到如下结果:

  #sh xxx.sh 2 3
      **
      ***
      *****
  
    一句话思路:看到这个第一反应就是循环呗。
  
#!/bin/bash
line1=$1
line2=$2
let line3=$1+$2
while [ $line1 -gt 0 ];do
        echo -n \*
        let line1=$line1-1
done
        echo
while [ $line2 -gt 0 ];do
        echo -n \*
        let line2=$line2-1
done
        echo
while [ $line3 -gt 0 ];do
        echo -n \*
        let line3=$line3-1
done
        echo
  
    知识点:如果你的第一反应是使用循环,那就进入一个死循环了,因为根本就没有规律。我们都知道,循环是依靠一定规律的。echo 的 -n参数。*在shell中是通配符,所以要加转义字符。(希望你能给出更好的解决方案!)
  
9、查找文件后缀是log的 三天前的文件删除
  
    一句话思路:查找就一定是find
  
    find / -name "*.log" -and -mtime +3 -exec rm -rf {} \;
  
    知识点:-mtime  + 代表后面数字之外的,- 就是之内的。
  
10、写一个脚本将目录下大于100kb的文件移动到/tmp下

      一句话思路:同上
  
    find ./ -size +100k -exec mv {}  /tmp \;
  
    知识点:-exec  {}  \; 标准写法,没有好办法,背吧。
  
11 、日志如下统计访问IP最多的前10个

192.168.0.6 - - [25/Nov/2010:13:55:10 +0800] "GET /cacti/p_w_picpaths/auth_login.gif HTTP/1.1" 200 21265 "http://192.168.0.104/cacti/graph_view.php?action=tree&tree_id=2&leaf_id=8&page=3" "Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 5.2; Trident/4.0; .NET CLR 1.1.4322; .NET CLR 2.0.50727; .NET CLR 3.0.4506.2152; .NET CLR 3.5.30729; InfoPath.1)"
192.168.0.6 - - [25/Nov/2010:13:55:14 +0800] "GET /favicon.ico HTTP/1.1" 404 287 "-" "Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 5.2; Trident/4.0; .NET CLR 1.1.4322; .NET CLR 2.0.50727; .NET CLR 3.0.4506.2152; .NET CLR 3.5.30729; InfoPath.1)
  
    这个题在前一篇中已经给出答案,这里就不再赘述。

    http://7648853.blog.51cto.com/4990508/851407
  
12、过滤出当前目录下所有以字母(不区分大小写)开头的文件
  
    一句话思路:过滤就是grep
  
    ls | grep -P "^[a-zA-Z]"
  
    ls | grep -P -i "^[a-z]"
  
    知识点:正则表达式,使用-i参数让grep命令不区分大小写。
  
13、文件A.txt内容为"12:34:68",只输出A.txt中的"34"
  
    一句话思路:提取内容就是awk
  
    awk  -F ":" '{print $2}' A.txt
  
    知识点:awk 域,-F参数指定分隔符,默认分隔符是空格。
   
14、用sed命令实现直接将文件B.TXT中的所有123替换成345
  
    一句话思路:没思路了,人家都说了用sed
  
    sed -i 's/123/456/g' B.TXT
  
    知识点:-i参数让sed修改文件,默认不修改源文件。题目中提到了所有字样,所以要使用g参数。
  
15、用sed修改文件mailbox.txt的20行的zhango为wang
  
    一句话思路:命题作文sed,没有瞎想空间
  
    sed -i '20s/zhango/wang/' mailbox.txt
  
    知识点:上题是全局,这题规定了行。如果写成这样"/20/",就是正则表达式了。
  
16、正则表达式,IP地址的匹配,写一下
  
    一句话思路:遥想当年,web开发程序员面试不出意外的第一道题。
  
    ([0-9]{1,3}\.){1,3}([0-9]){1,3}
  
    知识点:正则表达式,写个简单的,这个答案不严谨,但考虑到只是面试,所以将就将就也能用。
  
17、写出命令。统计日志文件weblog.log中 今天14:00~15:00的记录条数(时间格式:2011-01-01—15:30:11)
  
    一句话思路:第一反应,这个要用awk,分析统计嘛。可真要用awk麻烦就大了。
  
    sum14=`grep -c "2011-01-01-14" weblog.log`
    sum15=`grep -c "2011-01-01-15" weblog.log`
    echo $[$sum14+$sum15]

    知识点:grep命令-c参数,统计匹配的行数。shell中的数学计算。
  
18、求一组数的最大值和最小值

      一句话思路:运维越来越像开发了,冒泡法都有了。越来越难混了,一个运维不看手册,要看算法了。
  
    知识点:去看书吧,看算法的。

  
19、将当前目录所有文件扩展名改为log
  
    一句话思路:如果你的第一反应是使用find命令,那么恭喜你,你中了敌人的奸计,不是不能实现,是很麻烦。
  
for file in `ls ./ | grep -P "(.*)(\..*)"`;do  echo $file | mv $file `sed -r 's#(.*)(\..*)#\1.log#'`; done
  
for file in `ls ./ | grep -P "(.*)(\..*)"`;do  echo $file | mv $file `echo ${file%.**}`.log; done
  
    知识点:第一个方法中使用了sed,第二个方法中使用了字符操作,#从前向后数,%从后向前数。其实说白了,就是为了拼凑出 mv 参数1 参数2。其实很多时候,编写shell脚本的时候要学会反向推导,逆向思考。
  
       还有一种方法是使用cut命令,但如果遇到文件有两个扩展名的情况下就会出现问题。redhat as4 安装完成后,在root目录下会生成install.log  install.log.syslog这两个文件,如果使用cut就会出现错误。具体原因在这里就不说了。运维嘛,需要的是严谨!
  
20、用shell在/usr/local下 建立20个子目录 xunlei1-xunlei20,再在这个子目录下分别建255个子目录dir1-dir255,再在255个子目录下创建10000个文件xunlei1.html-xunlei10000.html
  
    一句话思路:这有啥,{}大括号呗。
  
    mkdir -p /usr/loca/xunlie{1..20}/dir{1..255}/

    touch   /usr/loca/xunlie{1..20}/dir{1..255}/xunlei{1..10000}.html  
   

    知识点:如果你就这么写上去,那你又中计了。为什么呢,因为超过了shell命令参数的最大限制。shell中参数的限制是:5452。所以要分着写。
  
    写到这里,不禁感叹,面试这件事情越来越难。本来面试就紧张,满怀期待,不仅要跟HR讨价还价,还要与技术主管斗智斗勇,好吧,人是活的,我们忍了。可连死的面试题都要处处小心。可话说回来,面试题做不出来,就算你跟诸葛亮对着骂街都能微操胜券也没用。

      在这里要特别感谢邰锴同学,这些shell题是他帮忙汇总整理出来的。

 
本文出自 “ 林肯” 博客,请务必保留此出处 http://president.blog.51cto.com/4990508/854249



1.如下是对api接口日志的截取,存放在check.log文件中
22:57:36|check|por1|117.136.15.67|4|username|fail|5|29|
22:57:36|check|por1|183.1.94.215|4|username|succ|1644841971|14|
22:57:36|check|pro2|0.0.0.0| |username|succ|162885433|6|
22:57:36|check|por2|0.0.0.0|9|username|fail|-4038|0|
22:57:36|check|por3|120.11.82.19|2|username|fail|5|49|
22:57:36|check|por4|172.16.86.82|0|username|succ|1548062613|1|
22:57:36|check|por2|123.125.156.135|9| |succ|1632786393|1|
22:57:36|check|por5|124.231.21.100|5|username|succ|224803739|3|
22:57:36|check|por4|172.16.86.82|0|username|succ|1505887155|1|
22:57:36|check|por2|0.0.0.0|9|username|succ|1343846051|1|
22:57:36|check|por6|113.193.202.138|8|username|succ|1729273615|1|
22:57:36|check|por6|116.75.149.20|8|username|succ|1729981552|1|
22:57:36|check|por5|116.5.164.94|5|username|succ|214405328|1|
22:57:36|check|por2|0.0.0.0|9|username|succ|1433162137|1|
22:57:36|check|por3|218.69.6.30|5|username|succ|28725136|42|
22:57:36|check|por2|0.0.0.0|8| |fail|5|4|
22:57:36|check|por5|123.115.102.222|5|243905232|succ|243905232|1|
22:57:36|check|por4|172.16.86.82|0|1011711900|succ|1011711900|39|
日志各字段代表的意义如下:
时间|接口名称|使用该接口的产品名称|调用接口的IP地址|用户类型|用户账号名称|接口返回结果(succ or fail)|当接口返回结果为“succ”时,该字段为用

户唯一编号;当接口返回结果为“fail”时,该字段为接口返回的错误代号|接口执行时间(毫秒级别)
问题:请使用shell命令的组合得到每个产品调用该接口成功时接口的平均执行速度,并按照执行速度由低到高排序(注:用户类型和用户账号名称为空的访问不

计算在内),以如下格式输出:
pro1 :0.0714286
pro2 :0.3333333
pro3 :0.0238095
pro4 :0.0731707
pro5 :0.6
pro6 :1

一句话思路:有计算、有排序,awk是唯一选择。统计总数的同时,还要统计出现次数,最后进行计算。
awk -F "|" '$(NF-3)~/succ/{por[$3]=por[$3]+$(NF-1);sum[$3]++}END{for(var in por)print var" :"por[var]/sum[var] | " sort -k2 -nr"}' check.log
 
知识点:awk数组,awk管道,为避免不等长使用NF变量

2.用一行命令实现:查找当前目录下(含子目录),文件内容中含有sina且文件名以".config"结尾的文件
一句话思路:批量按规则查找文件内容grep
grep -lr "sina" ./ | grep -P "(.*)(\.config$)"
知识点:grep -r 递归查找,-P支持perl正则表达式

3.用shell查询以“.”结尾的文件,并加上后缀“.ts”
一句话思路:在之前的曾经有过批量修改扩展名的实例,但这次有所不同,使用find命令就可以搞定

find ./ -name "*." -exec mv {} {}ts \;
知识点:find命令

4.假定某个web服务器访问log其中一行如下:

61.159.245.95 - - [30/Apr/2003:01:04:20 +0800] "GET / HTTP/1.1" 200 151 "http://www.baidu.com" "Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 

6.1; WOW64; Trident/4.0; SLCC2; .NET CLR 2.0.50727; .NET CLR 3.5.30729; .NET CLR 3.0.30729; Media Center PC 6.0; .NET4.0C; InfoPath.3; 

360SE)"
该LOG文件超过10万行,如果列出最后的10万行中请求最多前十位IP,显示如下的结果:
119 211.101.169.200
103 211.101.169.206
50 61.149.38.249
11 202.106.138.194
请用一行命令显示出上面的结果
 
一句话思路:之前有过类似的,这里不再赘述
awk '{ip[$1]++}END{for(var in ip)print ip[var],var |"sort -nr|head -n10"}' log


5.linux下ifconfig命令显示结果如下:
eth0      Link encap:Ethernet  HWaddr 00:0C:29:AA:E6:44
          inet addr:192.168.213.128  Bcast:192.168.213.255  Mask:255.255.255.0
          inet6 addr: fe80::20c:29ff:feaa:e644/64 Scope:Link
          UP BROADCAST RUNNING MULTICAST  MTU:1500  Metric:1
          RX packets:39962 errors:0 dropped:0 overruns:0 frame:0
          TX packets:27038 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:1000
          RX bytes:35108954 (33.4 MiB)  TX bytes:6573610 (6.2 MiB)
          Base address:0x2000 Memory:c9020000-c9040000

lo        Link encap:Local Loopback
          inet addr:127.0.0.1  Mask:255.0.0.0
          inet6 addr: ::1/128 Scope:Host
          UP LOOPBACK RUNNING  MTU:16436  Metric:1
          RX packets:1833 errors:0 dropped:0 overruns:0 frame:0
          TX packets:1833 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:0
          RX bytes:4840659 (4.6 MiB)  TX bytes:4840659 (4.6 MiB)
执行如下命令
/sbin/ifconfig eth0|grep 'inet '|sed 's/^.*addr://g'|sed 's/ Bcast.*$//g'
请写出命令的输出结果

    ip地址 犹豫了一下这个要不要写,在命令行里执行一下就行了。

6.多线程/多进程 程序同时访问相同的资源(例如:同时向一个文件里写数据)需要注意些什么?

    至少注意文件锁,读锁与写锁

7.写脚本实现,可以用shell,perl等。把文件B中有的,但是文件A中没有的所有行,保存为文件C,并统计C的行数

    diff B A | grep "<" | sed 's/< //' > C

8.脚本实现把/tmp/目录下所有创建超过7天的文件删除

    find /tmp -mtime +7 -exec rm -rf {} \;

9.把1 2 3 4 5 6按如下格式输出
1
2
3
4
5
6
如何实现

    echo 1 2 3 4 5 6 | sed "s# #\n#g"

10.设计一个shell程序,在2012年12月23日凌晨3点备份并压缩前一天/svn目录的所有内容,存放在/root/bak目录里,且文件名为如下形式svn.2008.05.06.tar.gz,试写脚本。

    at 201212230300
    at> find /svn -mtime +1 -and -mtime -2 -exec cp -r {} /root/bak \;
    at> tar -czf svn.2008.05.06.tar.gz /root/bak
 
     感谢何运涛同学,已经毕业的同学,薪水也不错。现在我们是同行了,这些题目是他帮忙整理的,原始版本都是照片,都是他一个一个字打上去的,尤其是第一题!
本文出自 “ 林肯” 博客,请务必保留此出处 http://president.blog.51cto.com/4990508/854647