免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
最近访问板块 发新帖
楼主: zooyo
打印 上一主题 下一主题

[游戏娱乐] 2012年ChinaUnix社区Shell编程大赛 [结束评审 公布部分答案](获奖名单已公布-5-24) [复制链接]

论坛徽章:
93
2015年辞旧岁徽章
日期:2019-10-10 10:51:15CU大牛徽章
日期:2014-02-21 14:21:56CU十二周年纪念徽章
日期:2020-10-15 16:55:55CU大牛徽章
日期:2014-02-21 14:22:07羊年新春福章
日期:2019-10-10 10:51:39CU大牛徽章
日期:2019-10-10 10:55:38季节之章:春
日期:2020-10-15 16:57:40ChinaUnix元老
日期:2019-10-10 10:54:42季节之章:冬
日期:2019-10-10 10:57:17CU大牛徽章
日期:2014-02-21 14:22:52CU大牛徽章
日期:2014-03-13 10:40:30CU大牛徽章
日期:2014-02-21 14:23:15
1 [报告]
发表于 2012-03-07 11:35 |显示全部楼层
今天没空……

论坛徽章:
93
2015年辞旧岁徽章
日期:2019-10-10 10:51:15CU大牛徽章
日期:2014-02-21 14:21:56CU十二周年纪念徽章
日期:2020-10-15 16:55:55CU大牛徽章
日期:2014-02-21 14:22:07羊年新春福章
日期:2019-10-10 10:51:39CU大牛徽章
日期:2019-10-10 10:55:38季节之章:春
日期:2020-10-15 16:57:40ChinaUnix元老
日期:2019-10-10 10:54:42季节之章:冬
日期:2019-10-10 10:57:17CU大牛徽章
日期:2014-02-21 14:22:52CU大牛徽章
日期:2014-03-13 10:40:30CU大牛徽章
日期:2014-02-21 14:23:15
2 [报告]
发表于 2012-03-13 15:23 |显示全部楼层
终于糊弄出来了,重在参与,重在参与,没想到都这么多页了,真热闹啊。

第一题:
  1. awk -F ' '
  2. awk -F '[ ]'
  3. awk -F '[ ]+'
  4. 三者有区别么?
复制代码
解:有。

  1. awk -F ' '      # 这句以任意空白符号为隔符,比如 tab 也可以匹配
  2. awk -F '[ ]'    # 这句以固定一个空格为隔符,tab 不可以匹配
  3. awk -F '[ ]+'   # 这句以一个或多个空格为隔符,tab 不可以匹配
复制代码
第二题:

  1. awk '/foo1/,/foo2/'
  2. sed -n '/foo1/,/foo2/p'
  3. 实现的功能一样么?
复制代码
解:一样,都是输出包含模式foo1和foo2之间的所有行

第三题:

  1. 如何用最简单的方法列举出 "a b c e f" 和"1 2 3" 的所有组合?
复制代码
解:这题没看的明白,是分别一个 abcef 这五个字母的组合,和 123 这三个数字的组合;还是 abcef 和 123 这五个字母和三个数字的组合?不过我觉得可能还是 a b c e f 分别取出一个字母和 1 2 3 分别取出一个数字的组合吧?
那就这样研究研究:

  1. [seesea2517@UC]$ echo {a,b,c,e,f}{1,2,3}
  2. a1 a2 a3 b1 b2 b3 c1 c2 c3 d1 d2 d3 e1 e2 e3 f1 f2 f3
复制代码
第四题:

  1. 字符串 'aaabcccaaabbbccc',去重复后,变为 'aaabcccbbb' , awk或sed实现,不使用管道。
复制代码
解:去重复后为啥bbb没去掉……真是头疼的事情。echo 后的 | 不算在限制中吧,不然用文件罗。

  1. [seesea2517@UC]$ echo "aaabcccaaabbbccc" | sed -r ':a; s/(.*)(.)(\2\2)(.*)\2\3(.*)/\1\2\3\4\5/; ta'
  2. aaabcccbbb
复制代码
第五题: 既然双引号中的\<newline>是续行符,为什么结果不是"foo  barabc def"?
解:题目中的\<newline>已经是变量内容中的一个字符了,只是与续行符“长的一样”,并没有续行的功能

第六题:foo也bar之间为什么只有一个空格?
解:没有加引号,则空格做为 echo 的参数分隔,任意个空格都相当于一个空格。输入以“一个空格”为分隔符:
引自 info echo:
'echo' writes each given STRING to standard output, with a space between each and a newline after the last one.

第七题:

  1. $ cat file
  2. 1
  3. 2
  4. a
  5. b
  6. c
  7. d
  8. c
  9. e
  10. 如何取到 a ~ c 之间的所有行:
  11. a
  12. b
  13. c
  14. d
  15. c
复制代码
解:

  1. [seesea2517@UC]$ sed -n 'H;${g;s/\n/,/g;s/^[^a]*a/a/;s/c[^c]*$/c/;s/,/\n/g;p}' file
  2. a
  3. b
  4. c
  5. d
  6. c
复制代码

  1. [seesea2517@UC]$ cat test.awk
  2. /a/ {if(la==0) la=NR}
  3. /c/ {lc=NR}
  4. END{
  5.     i=0
  6.     while (getline ln < FILENAME > 0)
  7.     {
  8.         ++i
  9.         if (i < la || i >lc)
  10.             continue
  11.         print ln
  12.     }
  13. }
  14. [seesea2517@UC]$ awk -f test.awk file
  15. a
  16. 2
  17. a
  18. b
  19. c
  20. d
  21. c
复制代码
第八题:

  1. $ seq 9
  2. 1
  3. 2
  4. 3
  5. 4
  6. 5
  7. 6
  8. 7
  9. 8
  10. 9
  11. 如果得到以下结果:
  12. 1 2 3
  13. 2 3 4
  14. 3 4 5
  15. 4 5 6
  16. 5 6 7
  17. 6 7 8
  18. 7 8 9
  19. 8 9
复制代码
解:总觉得应该用 xargs,没搞定……
就来一个挫的吧:

  1. seq 8 | awk '{print $1, ($1+1>=10 ? "" : $1+1), ($1+2>=10 ? "" : $1+2)}'
复制代码
第九题:

  1. 有一千台机器client0001、 client0002、......、client1000需要定期修改oracle这个用户的密码,另外一台机器server0000分别与它们建立了 ssh信任关系。请在server0000上用shell脚本生成一个随机字符串,然后批量连接这一千台机器并修改oracle用户的密码,这些 client机器统一使用前面生成的字符串作为新密码。密码的复杂度要求是:8位长度,至少1位小写字母,至少1位大写字母,至少1为数字。最后生成一份统计信息,记录哪些机器修改成功,哪些机器修改失败,并记录新的密码。
复制代码
解:
文件一:change_pwd.sh

  1. #!/bin/bash
  2. # change_pwd.sh
  3. # 批量更改密码
  4. # 创建者:seesea2517
  5. # 2012-03-12

  6. #---------------------------------------------------------------
  7. # 全局配置
  8. LENGTH_PASSWORD=8           # 密码长度
  9. MAX_THREAD=100              # 最大并发数
  10. USER="oracle"               # ssh登录用户及更改密码的目标用户
  11. PORT=22                     # ssh端口
  12. PREFIX="client"             # 目标机器名前缀
  13. FLAG_END="flag_end"         # 结束标志
  14. FILE_RESULT="log.txt"       # 操作结果日志,记录新密码,操作后成功与失败的机器

  15. #---------------------------------------------------------------
  16. # 全局变量
  17. new_password=""             # 随机新密码
  18. fd_control=4                # 并发控制队列描述符
  19. fd_result=5                 # 结果队列描述符

  20. #---------------------------------------------------------------
  21. # 函数定义

  22. # 生成一个随机字母
  23. # 返回:随机字母
  24. # 参数一:大小写标志,取值及意义如下
  25. #     1    - 生成小写
  26. #     2    - 生成大写
  27. #     其它 - 大小写随机
  28. random_char()
  29. {
  30.     local lower_chars="abcdefghijklmnopqrstuvwxyz"
  31.     local upper_chars="ABCDEFGHIJKLMNOPQRSTUVWXYZ"
  32.     local total_chars="$lower_chars$upper_chars"
  33.     local chars
  34.     local len

  35.     case "$1" in
  36.     1) chars=$lower_chars ;;
  37.     2) chars=$upper_chars ;;
  38.     *) chars=$total_chars ;;
  39.     esac

  40.     len=${#chars}

  41.     echo ${chars:$((RANDOM % len)):1}
  42. }

  43. # 生成一个随机数字
  44. # 返回:随机数字
  45. # 参数一:随机数上限,默认取值 10,即返回个位数
  46. random_number()
  47. {
  48.     local max_number

  49.     max_number=$1
  50.     if [ -z "$1" ]
  51.     then
  52.         max_number=10
  53.     fi

  54.     echo $((RANDOM % max_number))
  55. }

  56. # 生成指定长度的随机密码
  57. # 固定复杂度要求:至少一个大写一个小写一个数字
  58. # 返回:指定长度的随机字串
  59. # 参数一:字串长度
  60. random_password()
  61. {
  62.     local i
  63.     local len
  64.     local str
  65.     local flag
  66.     local flag_upper
  67.     local flag_lower
  68.     local flag_digit

  69.     len=$1
  70.     len=$((0 + len))

  71.     while true
  72.     do
  73.         str=""

  74.         flag_upper=0
  75.         flag_lower=0
  76.         flag_digit=0

  77.         for ((i = 0; i < len; ++i ))
  78.         {
  79.             flag=$(random_number 3)
  80.             case $flag in
  81.             1)
  82.                 str="$str$(random_char $flag)"
  83.                 flag_lower=1
  84.                 ;;
  85.             2)
  86.                 str="$str$(random_char $flag)"
  87.                 flag_upper=1
  88.                 ;;
  89.             *)
  90.                 str="$str$(random_number)"
  91.                 flag_digit=1
  92.                 ;;
  93.             esac
  94.         }

  95.         # 若生成字串长度不大于3,则没法达成复杂度要求,不继续处理
  96.         if [ $len -lt 3 ]
  97.         then
  98.             break
  99.         fi

  100.         # 若达到复杂度要求,则跳出循环,否则继续循环,重新生成字串
  101.         if ((flag_upper + flag_lower + flag_digit >= 3))
  102.         then
  103.             break
  104.         fi
  105.     done

  106.     echo $str
  107. }

  108. # 更改密码的回调函数
  109. # 1. 将结果输入到结果队列中
  110. # 2. 补充控制队列的长度
  111. #
  112. # 参数一:ssh登录的服务器名
  113. # 参数二:更改密码的操作结果
  114. sub_end()
  115. {
  116.     echo "xxx" >& $fd_control
  117.     echo "$1 $2" >& $fd_result
  118. }

  119. # 调用更改密码的expect脚本,然后以操作返回值回调主程序的处理函数
  120. # 参数一:ssh登录的用户名,同时也是做为改变密码的用户
  121. # 参数二:ssh登录的服务器名
  122. # 参数三:ssh登录端口
  123. # 参数四:更新用的新密码
  124. change_password()
  125. {
  126.     # 执行更改密码
  127.     # 测试用  ./xx.sh -> 文件内容:exit $((RANDOM % 3))
  128.     ./auto_passwd.exp $1 $2 $3 $3

  129.     # 操作结束后,登记操作结果
  130.     sub_end $2 $?
  131. }

  132. # 统计信息
  133. stat_info()
  134. {
  135.     local server_name
  136.     local result
  137.     local fail_list=""
  138.     local success_list=""

  139.     while true
  140.     do
  141.         # 获取结果
  142.         read -u$fd_result server_name result

  143.         # 如果是结束标志,则退出
  144.         if [ "$server_name" == "$FLAG_END" ]
  145.         then
  146.             break
  147.         fi

  148.         # 根据返回结果,记录到成功和失败列表中
  149.         if [ "$result" -eq 0 ]
  150.         then
  151.             success_list="$success_list $server_name"
  152.         else
  153.             fail_list="$fail_list $server_name"
  154.         fi
  155.     done

  156.     echo "新密码:$new_password"    >  $FILE_RESULT
  157.     echo "失败列表:$fail_list"     >> $FILE_RESULT
  158.     echo "成功列表:$success_list"  >> $FILE_RESULT
  159. }

  160. # 初始化
  161. init ()
  162. {
  163.     local file_name

  164.     # 创建控制并发用的 FIFO 队列
  165.     file_name="$.fifo"
  166.     mkfifo $file_name
  167.     exec 4<>$file_name
  168.     rm $file_name

  169.     # 创建结果存放的队列
  170.     file_name="$.fifo"
  171.     mkfifo $file_name
  172.     exec 5<>$file_name
  173.     rm $file_name

  174.     # 向 FIFO 队列写入MAX_THREAD行内容,表示有这么多的空位可以使用
  175.     for ((i = 0; i < $MAX_THREAD; ++i))
  176.     do
  177.         echo "xxx" >& $fd_control
  178.     done
  179. }

  180. # 主函数
  181. main()
  182. {
  183.     local server_name

  184.     # 初始化
  185.     init

  186.     # 生成新密码
  187.     new_password=$(random_password $LENGTH_PASSWORD)

  188.     # 对一千台机器进行处理
  189.     # 如果命名没有规则,则使用一个配置文件来做,这里只按例子简单处理
  190.     for (( i = 0; i <= 1000; ++i ))
  191.     do
  192.         # 向控制队列申请执行
  193.         read -u $fd_control

  194.         # 生成服务器名
  195.         server_name="0000$i"
  196.         server_name="$PREFIX${server_name:${#server_name}-4:4}"

  197.         # 后台调用更改密码,并行操作
  198.         change_password $USER $server_name $PORT $new_password &
  199.     done

  200.     # 等待全部子进程执行
  201.     wait

  202.     # 向结果队列写入新密码信息

  203.     # 向结果队列中写入结束标志
  204.     sub_end $FLAG_END

  205.     # 统计结果
  206.     stat_info
  207. }

  208. #---------------------------------------------------------------
  209. # 运行
  210. main
复制代码
文件二:auto_passwd.exp

  1. #!/usr/bin/expect
  2. # auto_passwd.exp
  3. # 自动更改密码
  4. # 创建者:seesea2517
  5. # 2012-03-12

  6. # 使用 expect 自动响应 passwd 来更改远程主机密码
  7. # 输入参数:
  8. # 参数一:登录用户名
  9. # 参数二:主机IP/或主机名
  10. proc auto_passwd {in_user in_ip in_port in_psw} {
  11.     set timeout 180
  12.     spawn ssh $in_user@$in_ip -p $in_port "passwd"

  13.     expect {
  14.         -nocase "password:"
  15.         {
  16.             send "$in_psw\r"
  17.             exp_continue
  18.         }

  19.         "successfully."
  20.         {
  21.             return 0
  22.         }

  23.         timeout
  24.         {
  25.             return -1
  26.         }
  27.     }
  28. }


  29. set in_user [lindex $argv 0]
  30. set in_ip   [lindex $argv 1]
  31. set in_port [lindex $argv 2]
  32. set in_psw  [lindex $argv 3]

  33. set ret [auto_passwd $in_user $in_ip $in_port $in_psw]
  34. exit $ret
复制代码
文件三(用于测试):xx.sh

  1. #!/bin/bash
  2. exit $((RANDOM % 3))
复制代码
第十题:

  1. Oracle数据库dbFirst里面有一张表employee1,包含两列:id和email。MySQL数据库dbSecond里面有一张表employee2,同样包含两列:id和 email。两个数据库的用户名都是myuser,密码都是mypass,两张表的数据量都在一千万行左右。请用shell脚本获取两张表的数据,然后比较出两张表中互不相同的id和email分别输出到文件different_id.txt和different_email.txt。
复制代码
解:

  1. #!/bin/bash

  2. # 没有用过Oracle数据库,也没有练习测试的环境,就照网上的“基础教程”依葫芦画瓢吧
  3. # 把 Oracle 数据库的 id 和 email 查询到文件中
  4. sqlplus myuser/mypass@dbFirst << EOF
  5. set heading off;
  6. spool id1.txt;
  7. select distinct id from dbFirst.employee1 order by id;
  8. spool off;
  9. spool email1.txt;
  10. select distinct email from dbFirst.employee1 order by email;
  11. spool off;
  12. exit;
  13. EOF

  14. # 把 Mysql 数据库的 id 和 email 查询到文件中
  15. mysql -umyuser -pmypass --column-names=0 --execute='select distinct id from dbFirst.employee1 order by id;' > id2.txt
  16. mysql -umyuser -pmypass --column-names=0 --execute='select distinct email from dbFirst.employee1 order by email;' > email2.txt

  17. # 比较两个结果
  18. diff -abBH id1.txt id2.txt | grep -E "<|>" > different_id.txt
  19. diff -abBH mail1.txt mail2.txt | grep -E "<|>" > different_email.txt
复制代码

论坛徽章:
93
2015年辞旧岁徽章
日期:2019-10-10 10:51:15CU大牛徽章
日期:2014-02-21 14:21:56CU十二周年纪念徽章
日期:2020-10-15 16:55:55CU大牛徽章
日期:2014-02-21 14:22:07羊年新春福章
日期:2019-10-10 10:51:39CU大牛徽章
日期:2019-10-10 10:55:38季节之章:春
日期:2020-10-15 16:57:40ChinaUnix元老
日期:2019-10-10 10:54:42季节之章:冬
日期:2019-10-10 10:57:17CU大牛徽章
日期:2014-02-21 14:22:52CU大牛徽章
日期:2014-03-13 10:40:30CU大牛徽章
日期:2014-02-21 14:23:15
3 [报告]
发表于 2012-03-13 15:31 |显示全部楼层
本帖最后由 seesea2517 于 2012-03-13 15:35 编辑

忘记说明测试环境了:

  1. [seesea2517@UC ~]$ uname -a
  2. Linux UC 2.6.18-128.2.1.el5 #1 SMP Tue Jul 14 06:39:56 EDT 2009 i686 i686 i386 GNU/Linux

  3. [seesea2517@UC ~]$ bash --version
  4. GNU bash, version 3.2.25(1)-release (i686-redhat-linux-gnu)
  5. Copyright (C) 2005 Free Software Foundation, Inc.

  6. [seesea2517@UC ~]$ awk --version
  7. GNU Awk 3.1.5

  8. [seesea2517@UC ~]$ sed --version
  9. GNU sed version 4.1.5

  10. [seesea2517@UC ~]$ mysql -uroot -p
  11. Enter password:
  12. Welcome to the MySQL monitor.  Commands end with ; or \g.
  13. Your MySQL connection id is 937 to server version: 4.0.26-log

  14. [seesea2517@UC ~]$ mysql --version
  15. mysql  Ver 12.22 Distrib 4.0.26, for pc-linux-gnu (i686)

  16. [seesea2517@UC ~]$ expect -v
  17. expect version 5.43.0
复制代码

论坛徽章:
93
2015年辞旧岁徽章
日期:2019-10-10 10:51:15CU大牛徽章
日期:2014-02-21 14:21:56CU十二周年纪念徽章
日期:2020-10-15 16:55:55CU大牛徽章
日期:2014-02-21 14:22:07羊年新春福章
日期:2019-10-10 10:51:39CU大牛徽章
日期:2019-10-10 10:55:38季节之章:春
日期:2020-10-15 16:57:40ChinaUnix元老
日期:2019-10-10 10:54:42季节之章:冬
日期:2019-10-10 10:57:17CU大牛徽章
日期:2014-02-21 14:22:52CU大牛徽章
日期:2014-03-13 10:40:30CU大牛徽章
日期:2014-02-21 14:23:15
4 [报告]
发表于 2012-04-16 23:57 |显示全部楼层
这几天没空来论坛,不小心发现居然得奖了,谢谢评委手下留情啊~看了参考答案和walker的解答真是开眼了。

现在没有环境,在cygwin下测试mkpasswd好像不能生成密码的样子:

  1. $ mkpasswd -l8
  2. mkpasswd (435): [53] 找不到网络路径。

  3. $ mkpasswd --help
  4. Usage: mkpasswd [OPTIONS]...
  5. Print /etc/passwd file to stdout

  6. Options:
  7.    -l,--local [machine[,offset]]
  8.                            print local user accounts with uid offset offset
  9.                            (from local machine if no machine specified)
  10.    -L,--Local [machine[,offset]]
  11.                            ditto, but generate username with machine prefix
复制代码
有环境的时候再试试。

论坛徽章:
93
2015年辞旧岁徽章
日期:2019-10-10 10:51:15CU大牛徽章
日期:2014-02-21 14:21:56CU十二周年纪念徽章
日期:2020-10-15 16:55:55CU大牛徽章
日期:2014-02-21 14:22:07羊年新春福章
日期:2019-10-10 10:51:39CU大牛徽章
日期:2019-10-10 10:55:38季节之章:春
日期:2020-10-15 16:57:40ChinaUnix元老
日期:2019-10-10 10:54:42季节之章:冬
日期:2019-10-10 10:57:17CU大牛徽章
日期:2014-02-21 14:22:52CU大牛徽章
日期:2014-03-13 10:40:30CU大牛徽章
日期:2014-02-21 14:23:15
5 [报告]
发表于 2012-04-17 00:01 |显示全部楼层
回复 79# send_linux


    包包是?有图么?

论坛徽章:
93
2015年辞旧岁徽章
日期:2019-10-10 10:51:15CU大牛徽章
日期:2014-02-21 14:21:56CU十二周年纪念徽章
日期:2020-10-15 16:55:55CU大牛徽章
日期:2014-02-21 14:22:07羊年新春福章
日期:2019-10-10 10:51:39CU大牛徽章
日期:2019-10-10 10:55:38季节之章:春
日期:2020-10-15 16:57:40ChinaUnix元老
日期:2019-10-10 10:54:42季节之章:冬
日期:2019-10-10 10:57:17CU大牛徽章
日期:2014-02-21 14:22:52CU大牛徽章
日期:2014-03-13 10:40:30CU大牛徽章
日期:2014-02-21 14:23:15
6 [报告]
发表于 2012-04-19 10:41 |显示全部楼层
回复 88# waker
原来如此,见多识广才能做事效率啊,不然自己整得多麻烦。

  1. File: *manpages*,  Node: mkpasswd,  Up: (dir)

  2. MKPASSWD(1)                                                        MKPASSWD(1)

  3. NAME
  4.        mkpasswd - generate new password, optionally apply it to a user

  5. SYNOPSIS
  6.        mkpasswd [ args ] [ user ]

  7. INTRODUCTION
  8.        mkpasswd generates passwords and can apply them automatically to users.
  9.        mkpasswd is based on the code from Chapter  23  of  the  O’Reilly  book
  10.        "Exploring Expect".

  11. USAGE
  12.        With no arguments, mkpasswd returns a new password.

  13.             mkpasswd

  14.        With a user name, mkpasswd assigns a new password to the user.

  15.             mkpasswd don

  16.        The passwords are randomly generated according to the flags below.

  17. FLAGS
  18.        The -l flag defines the length of the password.  The default is 9.  The
  19.        following example creates a 20 character password.

  20.             mkpasswd -l 20

  21.        The -d flag defines the minimum number of digits that must  be  in  
复制代码

论坛徽章:
93
2015年辞旧岁徽章
日期:2019-10-10 10:51:15CU大牛徽章
日期:2014-02-21 14:21:56CU十二周年纪念徽章
日期:2020-10-15 16:55:55CU大牛徽章
日期:2014-02-21 14:22:07羊年新春福章
日期:2019-10-10 10:51:39CU大牛徽章
日期:2019-10-10 10:55:38季节之章:春
日期:2020-10-15 16:57:40ChinaUnix元老
日期:2019-10-10 10:54:42季节之章:冬
日期:2019-10-10 10:57:17CU大牛徽章
日期:2014-02-21 14:22:52CU大牛徽章
日期:2014-03-13 10:40:30CU大牛徽章
日期:2014-02-21 14:23:15
7 [报告]
发表于 2012-05-24 09:37 |显示全部楼层
回复 101# send_linux


    需要提供联系方式吧,怎样提供联系方式呢?
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP