Chinaunix

标题: ChinaUnix技术实践之四----Shell编程大赛! [打印本页]

作者: send_linux    时间: 2011-05-15 23:51
标题: ChinaUnix技术实践之四----Shell编程大赛!
大赛结果公布,奖品我们会第一时间快递给各位!

http://bbs.chinaunix.net/thread-3567765-1-1.html

Shell版块是ChinaUnix社区内讨论比较热烈的技术版块之一。之前我们已经成功举办了PHP、C/C++和Perl的编程大赛,今天我们举办第四期---Shell编程大赛,发挥您的技术之长,赢取我们为优胜者准备的丰富奖品,欢迎大家踊跃参加!

第一期:PHP编程大赛 http://bbs.chinaunix.net/thread-1788191-1-1.html
第二期:C/C++编程大赛http://bbs.chinaunix.net/thread-1820953-1-1.html
第三期:Perl编程大赛http://bbs.chinaunix.net/thread-1860259-1-1.html

参赛要求:参与活动必须是chinaunix社区的注册会员

点击注册: http://sso.chinaunix.net/Register

大赛日程:

参赛时间:2011.05.15~2011.06.05

评选时间:2011.06.06~2011.06.16

结果公布:2011.06.20

奖项设置:
一等奖:3名,最先正确完成10道题的三名用户,赠送微软IE3.0复刻版鼠标一个。
二等奖:5名,,获奖者为最先正确完成8道试题的五名用户,赠送特别定制版ChinaUnix商务衬衫。
三等奖:10名,获奖者为最先正确完成6道试题的十名用户,赠送ChinaUnix 限量版水杯一个。


参赛细则:
(1)代码规范:使用各种标准shell,awk,sed,采用编程标准可以使项目更加顺利地完成。
(2)性能:应用程序可以运行与高效运行是两个层次,保证程序的最佳效率。
(3)简洁:写代码是一种艺术。除了正确的缩进、大小写、命名规则之外,请时刻牢记爱因斯坦的名言--简单就是美。
(4)每位会员可以发表多个代码,以最高评价为准,不可重复获奖;
(5)提交代码请跟帖发表,并附相关系统环境及编译环境说明。
评选获奖的依据:答题的时间及答题的质量为依据,邀请嘉宾作为评选人。

代码提交:
参赛者以跟帖的方式提交代码,相似代码以最先提交为准,谁最早提交谁优秀。
注:严禁抄袭,一经发现,取消评选资格;


大赛评委团:
waker
Shell_HAT
cjaizss
blackold

大赛联系人:
send_linux 站内联系或者qq:19286680

大赛试题:
问题1:
用最简洁的命令列出当前目录下的一级子目录,可以不包含隐藏目录(目录名以.开头的目录)


问题2:
GNU sed 提供了-i选项,为什么有人说sed -i 并不象 ed 一样真正的编辑文件?(提示:观察文件改变前后的inode)

问题3:
用shell写一个cgi脚本,提供一个简单的webmail介面,将本地的一个文件通过web服务器发送到指定的邮箱

问题4:
awk -F'' 与 awk -F '' 一样吗?


问题5:
这条语句有什么作用?
sed -if /script/scr.sedcc test.txt


问题6:
#!/bin/sh
# the next line restarts using tclsh \
exec tclsh "$0" "$@"

是如何执行的?与"#!/usr/local/bin/tclsh"相比,它有什么优点?


问题7:
#!/bin/sed -f"  shebang 后可有其它字符吗?为什么?



问题8:
GNU awk的$1=$1到底有什么作用?$0=$0呢?


问题9:
写一个shell脚本,输出CU现有的版面和相应版主,并统计有多少个版面及多少个版主。


问题10:
人机五子棋。原始规则(无禁手),最好加上标准规则,三手交换(即黑下第二手之后白可以提出交换),五手两打,黑三三禁手,黑四四禁手,黑长连禁手(超过5个子相连),逢五无禁手。白无禁手,长连也算胜。关键在于人机对下。

作者: xiaopan3322    时间: 2011-05-15 23:57
本帖最后由 xiaopan3322 于 2011-05-16 21:46 编辑

沙发???

突然感觉自己水平好烂好烂,估计能答对一半就不错了……
总觉得第一个回答的人有点亏啊,有优惠不,哈哈……

1.
补充一个(应该还没人答过吧)。
这题我佩服SS兄,echo */这条命令用的真好,之前确实没想到……
  1. tree -d -L 1
复制代码
  1. ls -d */
复制代码
其实还有一个不算办法的办法(因为会计算大小,所以目录很大是会很慢,但是确实可以算一条简洁的命令):
  1. du --max-depth=1
复制代码
2.
区别在于交互式,因为sed只适用于非交互式的场合(可以认为这是一种弊端,因为会有临时文件产生)。
同时,使用sed -i编辑文件会导致文件的inode改变。

3.
看来我最开始的理解是对的,
Shell的cgi其实并不难,无非就是用html的语法罢了,这里有个前提,就是系统已经启动了apache:
  1. [root@hzlinea08 ~]# /opt/lampp/lampp start
  2. Starting XAMPP for Linux 1.7.4...
  3. XAMPP: Starting Apache with SSL (and PHP5)...
  4. XAMPP: Starting MySQL...
  5. XAMPP: Starting ProFTPD...
  6. XAMPP for Linux started.
  7. [root@hzlinea08 ~]# hostname              
  8. hzlinea08.china.nsn-net.net
复制代码
为了表达清楚,我在第四步附上图片:
这道题分为四个步骤:
1). 启动apache(我偷懒了,用的是lamp)
2). 准备shell脚本(位于/opt/lampp/cgi-bin,并确保此脚本有可执行权限),如下:
  1. [root@hzlinea08 cgi-bin]# pwd
  2. /opt/lampp/cgi-bin
  3. [root@hzlinea08 cgi-bin]# cat mail
  4. #!/bin/sh

  5. # Print out necessary header and empty line
  6. echo -e "Content-type: text/html\n"

  7. # Print out a title and text. Note the HTML tags in the strings.
  8. echo "<TITLE>Simple mail system</TITLE>"
  9. echo "<H1 align=center>Simple mail system</H1>"
  10. echo "<hr>"
  11. echo "<b>Mail to list: </b>xiaopan3322@gmail.com</br>"
  12. echo "<b>Mail attachment: </b>urfile</br>"
  13. if [ -e urfile ]; then
  14.     (echo "contents"; uuencode urfile file) | mail -s "subject" xiaopan3322@gmail.com
  15.     echo "<b>Sending completed at: </b>`date +"%a %b %e, %Y"`</br>"
  16. else
  17.     echo "<b></br>Error, the urfile doesn't exist!!!</br></b>"
  18. fi

  19. # Clean up HTML page. Note the ending bold tag.
  20. #echo "</b>"
  21. echo "<hr>"
  22. echo "<H1></H1>"
复制代码
3). 准备index.php(位于/opt/lampp/htdocs):
  1. [root@hzlinea08 htdocs]# pwd
  2. /opt/lampp/htdocs
  3. [root@hzlinea08 htdocs]# cat index.php
  4. <A HREF="/cgi-bin/mail?/opt/lampp/cgi-bin/mail">Click here to sending mail</A>
复制代码
4). 在任意一台能够访问此机器的机子上,敲入hostname/ip:
主界面:

发送成功界面:

发送失败界面:


4.
不一样,在这里,第一种写法有误。

5.
sed调用文件/script/scr.sedcc执行,对test.txt直接处理

6.
首先说执行过程:
  1. 第一种会导致sh和tclsh都去执行脚本,exec仅通过sh执行,sh先执行脚本,把第二行作为注释,然后执行第三行,当执行到exec的时候停止sh的处理,转而启用tclsh,这个时候tclsh会重新将整个脚本再执行一次,由于这个时候第二行末尾有个续行符,所以tclsh将所有三行都当成了注释。
复制代码
再来说优点:
第一种写法好,如果没有记错的话,好处应该有三点:

  1. 1). tclsh脚本可以位于任意位置(只要是在$PATH中,shell能找到的就行),也就是说并不需要讲绝对路径写到脚本中去
  2. 2). 它能够突破文件名为30个字符的限制
  3. 3). 这种写法甚至在tclsh本身是shell脚本的时候也能执行
复制代码


7.

起初我就感觉这道题应该写错了,更新后又仔细的看了下,这回终于理解题意了。
答案如下:
不能!!!(空格可以有)
对于Shebang lines(即#!打头的行),一般只允许在解释器后面跟一段空格,这也就是为什么所有sed的参数不能分开的应用于Shebang line的原因(比方说你不能想当然的写成#!/usr/bin/sed -E -f,因为这是不允许的)。

8.
这应该是这个动作对awk做的一次欺骗,目的就是为了让OFS生效,NF+=0也能达到同样的效果。$0=$0不能。

9.
补上,写的比较垃圾,不过功能可以实现
  1. #!/bin/bash
  2. :>moderator_num
  3. main_url="http://bbs2.chinaunix.net"
  4. wget -q "$main_url" -O index.html
  5. Total_pages=`grep -o '^<a href="forum-.*.html" >.*a>' index.html | wc -l`
  6. sub_url=(`grep -o '^<a href="forum-.*.html" >.*a>' index.html | grep -o 'forum-.*html' | tr '\n' ' '`)
  7. sub_page=(`grep -o '^<a href="forum-.*.html" >.*a>' index.html | awk -F'[<>]' '{print $3}' | tr '\n' ' '`)
  8. for (( i=0; i<${#sub_url[@]}; i++ )); do
  9.     moderator_list=(`wget -qO- $main_url/${sub_url[i]} | sed -rn '/^<p id="modedby">/{n;p}' | sed 's/<[^>]*>//g' | awk -F: '{print $2}'`)
  10.     echo ${#moderator_list[@]} >> moderator_num 2>&1
  11.     echo -e "${sub_page[i]}: ${moderator_list[@]}"
  12. done
  13. Total_moderators=`awk '{sum+=$1}END{print sum}' moderator_num`
  14. echo "Total pages of Chinaunix: $Total_pages"
  15. echo "Total moderator of Chinaunix: $Total_moderators"
复制代码
10.
这题,无条件放弃。(我居然连规则都没看懂,汗)
作者: zooyo    时间: 2011-05-16 00:01
提示: 作者被禁止或删除 内容自动屏蔽
作者: chenbin200818    时间: 2011-05-16 00:59
发现好多都不会 之前也没听说
太受打击了
之前还认为自己shell很牛
作者: xiaopan3322    时间: 2011-05-16 01:09
回复 4# chenbin200818


    牛这个字眼都是相对的……要看和谁比……日子长了,说不定你就是第二个黑哥……
作者: yinyuemi    时间: 2011-05-16 05:11
本帖最后由 yinyuemi 于 2011-06-22 05:42 编辑

凑凑热闹

1:
  1. echo */
复制代码
2:
因为sed -i的执行过程:先产生一个临时文件,然后把结果输出到这个文件,
最后把这个文件重命名为原来的文件,所以当用ls -i查看编辑前后的文件会看到inode值是不同的.
ed是交互式的,是真正的in-place edit.
3.

  1. #!/bin/bash
  2. echo "Content-type: text/html"
  3. read -p '输入文件名: ' subject
  4. read -p '输入邮箱地址: ' mail_address
  5. mail -s '$subject' '$mail_address'
  6. echo "done"
复制代码
4.
不一样,-F''的话awk无法解读-F变量。
5.
--sed执行脚本(-f)/script/scr.sedcc,直接编辑修改(-i)test.txt--这道题彻底失败,想当然了
想大家学习!
6.
不知道
7.
不可以,会报错,
-f后面的会错误地被解释为文件名
8.
$1=$1可以使OFS生效,$0=$0可以使FS生效。

  1. echo '1 1 1
  2. 2 2 2' |awk 'NR==1{OFS=":";$1=$1;print}NR==2{OFS="#";$1=$1;print}'
  3. 1:1:1
  4. 2#2#2

  5. echo '1 1 1
  6. 2 2 2' |awk 'NR==1{OFS=":";$0=$0;print}NR==2{OFS="#";$0=$0;print}'
  7. 1 1 1
  8. 2 2 2


  9. echo '1:1:1
  10. 2#2#2' |awk 'NR==1{FS=":";$1=$1;print $1}NR==2{FS="#";$1=$1;print $1}'
  11. 1:1:1
  12. 2#2#2

  13. echo '1:1:1
  14. 2#2#2' |awk 'NR==1{FS=":";$0=$0;print $1}NR==2{FS="#";$0=$0;print $1}'
  15. 1
  16. 2
复制代码
9.

  1. ./script.sh >outputfile


  2. cat script.sh

  3. #!/bin/bash
  4. wget -qO- "http://bbs.chinaunix.net/index.shtml" |\
  5. awk '/^<a.*href.*forum.*html" >/{sub(/<a href="/,"http://bbs.chinaunix.net/");gsub(/" >|<\/a>/," ");print}' |\
  6. while read line1 line2
  7. do
  8. wget -qO- $line1 |\
  9. awk '/^<p id="modedby">/{getline line;gsub(/<[^>]*>|,/,"",line);printf "'"$line2"': ";print line }'
  10. done |\
  11. awk -F: '{print; {if($NF!~/\*$/) {s=split($NF,a," ");for(i=1;i<=s;i++) b[a[i]]} else {t++;z=z?z" "$1:$1}}}END{print "统计结果: CU共有"NR"个版面, "length(b)"个版主, 其中有"t"个版面的斑竹空缺,分别是\""z"\""}'
复制代码
10.
有时间的话再试试
作者: 惟吾无为    时间: 2011-05-16 08:02
我自认功力不足...

不过第一题怎么没人 ls */
作者: waker    时间: 2011-05-16 08:37
俺再解释一下问题三吧,回答过的可以重新回答

本地是指客户端机器,CGI脚本由web服务器运行,二者在逻辑上不是同一机器
这个cgi脚本的目的是让用户可以通过浏览器将自己机器上的文件发给他人,就象gmail web介面的附件功能一样,介面和功能可以简化,但上传文件和发送文件的步骤要体现出来
作者: ashlv    时间: 2011-05-16 08:47
其实有点想做最后一题,可是老板在后面虎视眈眈,就算了,今晚再来看看
作者: xinyv    时间: 2011-05-16 09:14
本帖最后由 xinyv 于 2011-06-02 11:59 编辑

1.
  1. find ./* -maxdepth 0 -type d
复制代码
2.

  1. 通过跟踪可以看到    ed  的操作过程是
  2. write(4, "a\n1\n", 4)
  3. close(4)
  4. 通过跟踪可以看到  sed  的操作过程是 rename("./sed6wKWPx", "aa")
复制代码
总结: ed 是直接编辑文件,sed 是生成临时文件,然后改名实现的。
3.

  1. #!/bin/bash
  2. echo -e "Content-type: text/html\n"

  3. if (( $# == 0 ));then
  4. # main
  5. cat <<EOF
  6. <HTML>
  7.   <H1><center>$(date +%F) 简单发送邮件CGI</center></H1>
  8.   <HR>
  9.      <form action="${HTTP_REFERER}?send" method="POST" enctype="multipart/form-data">
  10.        <p align="left">
  11.        收件人:&nbsp<input type="text"  name="Address" size="60"><br><br>
  12.        标&nbsp&nbsp&nbsp&nbsp题:&nbsp<input type="text"  name="Subject" size="60"><br><br>
  13.        正&nbsp&nbsp&nbsp&nbsp文:&nbsp<textarea rows="10" name="Info" cols="50"></textarea><br><br>
  14.        附&nbsp&nbsp&nbsp&nbsp件:&nbsp<input type="file" name="mf" size=51/><br><br>
  15.        <input type=submit value="send"><input type="reset" value="Clear"> </p>
  16.      </form>
  17.   <HR>
  18. </HTML>
  19. EOF
  20. else
  21.     if [[ ${QUERY_STRING} == "send" ]] && [[ ${REQUEST_METHOD} = POST ]];then
  22.         cd /tmp
  23.         cat - >/tmp/$.mf
  24.         typeset -x _F=$(awk '{if($0~/^Content-Disposition.+filename/)print gensub(".+filename=\"(.+)\".*","\\1","g",$0)}' $.mf)
  25.         typeset -x State="${CONTENT_TYPE##*=}"
  26.         if [ ! -z ${_F} ];then
  27.             typeset -x $(awk 'BEGIN{FS="\r\n";RS=ENVIRON["State"]}{if($2~/Address/)print "rcptto=\x22"$4"\x22";
  28.                                                   if($2~/Subject/)print "subject=\x22"$4"\x22"
  29.                                                   if($2~/Info/)print "info=\x22"$4"\x22"
  30.                                                   if($2~/filename/)printf("%s",$5)>ENVIRON["_F"]
  31.                                    }' $.mf)
  32.             echo "${info}"|mutt -a ${_F} -s "${subject}" ${rcptto}
  33.         else
  34.             echo "${info}"|mutt -s "${subject}" ${rcptto}
  35.         fi
  36.         rm -f $.mf ${_F}
  37.     fi
  38.     cat <<EOF
  39. <HTML>
  40.   <H1><center>$(date +%F) 简单发送邮件CGI</center></H1>
  41.   <HR>
  42.   <H2><center>邮件已经发送,请查收.</center></H2>
  43.   <head>
  44.       <title>Redirect</title>
  45.       <meta http-equiv="refresh" content="2;url=${HTTP_REFERER}">
  46.   </head>
  47.   <HR>
  48. </html>
  49. EOF
  50. fi
复制代码
4.

  1. awk -F '' 可以使用 NULL 为分隔符。
  2. awk -F''  不能使用 NULL 为分隔符。起引号内必须赋值.  
复制代码
5.

  1. 按照脚本 scr.sedcc 修改 text.txt 文件。
复制代码
6.

  1. 这是 tclsh 帮助里的一段话,看过 tclsh 帮助的童鞋们应该都不陌生。

  2. 这有三个好处
  3. 1、bash 可以在路径搜索二进制文件存放位置。
  4. 2、文件名没有30个字符的限制
  5. 3、tclsh 可以直接运行脚本把 第二行的  \ 当成转义
复制代码
7.

  1. 不可以,sed 会把后面紧着的当文件名处理,当然空格例外。
复制代码
8.

  1. $1=$1 用当前的OFS重构 $0      NF 不改变
  2. $0=$0 用当前的 FS重构 $1..$N  NF 会改变
复制代码
9.有两个版打不开,没权限,所以无法统计那两个版面的版主:[频道交流区、版主会议室]
   版主里面有个叫"CU管理员" 的占算一名版主名额。

  1. #!/bin/bash
  2. #
  3. PATH=${PATH}:/sbin:/usr/sbin:/usr/local/bin
  4. Url="http://bbs.chinaunix.net"
  5. N=0
  6. curl --connect-timeout 10 -m 60 --retry 5 -A "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0)" ${Url} -o /tmp/tempfile 2>/dev/null
  7. awk '{if($0~"bold subject"){getline;getline;printf("%s %s\n",gensub("href..(.+)\"","\\1","g",$2),gensub(">|<|/a","","g",$3))}}' /tmp/tempfile >/tmp/tempfile1
  8. while read Url1 Name;do
  9.     let N++
  10.     printf "%-2s -- %-20s%-20s\n" ${N} ${Name} "[${Url}/${Url1}]" >>/tmp/tempfile3
  11.     curl --connect-timeout 10 -m 60 --retry 5 -A "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0)" ${Url}/${Url1} -o /tmp/tempfile2 2>/dev/null
  12.     awk 'BEGIN{FS="[<>]"}{if($1=="版主: ")for(i=3;i<NF;i+=4)print "版主: "$i}' /tmp/tempfile2 >>/tmp/tempfile3
  13. done</tmp/tempfile1
  14. awk '{printf("%-15s",($1=="版主:")?"["$2"] ":"\n\n"$0"\n")}' /tmp/tempfile3
  15. echo '#------------------------------------------------------------------#'
  16. awk '{if($0~/^版主/){A[$0]++}else{B[$0++]}}END{printf("CU现有版面[%d]\t版主[%d]个\n",length(B),length(A))}' /tmp/tempfile3
  17. rm -f /tmp/tempfile*
复制代码
10.

  1. #!/bin/bash
  2. PATH=${PATH}:/sbin:/usr/sbin:/usr/local/bin
  3. export E33="^[[" Y_X=(20 30) Color _Color Pie=$(echo -e "  ")

  4. function create_box() {
  5.   typeset y x
  6.   for ((y=10;y<=30;y++));do
  7.     for ((x=10;x<=50;x+=2));do
  8.       if (( x==10 )) || (( y==10 )) || (( x==50 )) || (( y==30 ));then
  9.         echo -e "${E33}${y};${x}H${E33}43m  ${E33}49m\n"
  10.       else
  11.         if (( y%2==1 ));then
  12.           typeset C1=47 C2=49
  13.         else
  14.           typeset C1=49 C2=47
  15.         fi
  16.         if (( x%4==0 ));then
  17.           echo -e "${E33}${y};${x}H${E33}${C1}m${Pie}${E33}${C2}m${Pie:-  }${E33}49m";
  18.           export box_${y}_${x}=${C1} box_${y}_$((x+2))=${C2}
  19.         fi
  20.       fi
  21.     done
  22.   done
  23.   return 0
  24. }
  25. function _Display() {
  26.   if (( $# == 3 ));then
  27.     O_color=box_${Y_X[0]}_${Y_X[1]}
  28.     echo -e "${E33}${Y_X[0]};${Y_X[1]}H${E33}${!O_color}m${Pie}${E33}49m"
  29.     case "$3" in
  30.       A)
  31.       (( --Y_X[0]<11 )) && ((Y_X[0]++))
  32.       ;;
  33.       B)
  34.       (( ++Y_X[0]>29 )) && ((Y_X[0]--))
  35.       ;;
  36.       C)
  37.       (( (Y_X[1]+=2)>48 )) && ((Y_X[1]-=2))
  38.       ;;
  39.       D)
  40.       (( (Y_X[1]-=2)<12 )) && ((Y_X[1]+=2))
  41.       ;;
  42.     esac
  43.     echo -e "${E33}${Y_X[0]};${Y_X[1]}H${E33}46m${Pie}${E33}49m"
  44.   fi
  45.   return 0
  46. }
  47. function control() {
  48.   while true;do
  49.     read -s -n1 _T 2>/dev/null
  50.     INPUT3=${INPUT2}
  51.     INPUT2=${INPUT1}
  52.     INPUT1=${_T}
  53.     if [[ "${INPUT3}${INPUT2}${INPUT1}" =~ "${E33}"[ABCD] ]];then
  54.       _Display ${Y_X[@]} ${INPUT1}
  55.     elif [[ "[${_T}]" == "[]" ]];then
  56.       O_color=box_${Y_X[0]}_${Y_X[1]}
  57.       if [[ "${!O_color}" == 4[79] ]];then
  58.         export box_${Y_X[0]}_${Y_X[1]}=42
  59.         echo -e "${E33}${Y_X[0]};${Y_X[1]}H${E33}${!O_color}m${Pie:-  }${E33}49m"
  60.         Check box_${Y_X[0]}_${Y_X[1]}
  61.         if [ $? != 0 ];then Exit;fi
  62.         AI
  63.       fi
  64.     elif [[ "${_T}" == [Qq] ]];then Exit;fi
  65.   done
  66.   return 0
  67. }
  68. function Check() {
  69.   Color=${!1}
  70.   for h in 0 1 3 2;do
  71.     j=0
  72.     for i in -4 -3 -2 -1 0 1 2 3 4 ;do
  73.       if (( h > 1 ));then
  74.         _Color="box_$((Y_X[0]+i*$((2*h-5))))_$((Y_X[1]+2*i*$(((2*h-5)**2))))"
  75.       else
  76.         _Color="box_$((Y_X[0]+i*${h}))_$((Y_X[1]+2*i*$((! h))))"
  77.       fi
  78.       if [[ "${!_Color:-43}" == "${Color}" ]];then
  79.         if (( ++j == 5 ));then
  80.           if (( h > 1 ));then
  81.             for ((k=i;k>i-5;k--));do
  82.               echo -e "${E33}$((Y_X[0]+k*$((2*h-5))));$((Y_X[1]+2*k*$(((2*h-5)**2))))H${E33}${Color}m${E33}5m[]${E33}25m"
  83.             done
  84.           else
  85.             for ((k=i;k>i-5;k--));do
  86.               echo -e "${E33}$((Y_X[0]+k*${h}));$((Y_X[1]+2*k*$((! h))))H${E33}${Color}m${E33}5m[]${E33}25m"
  87.             done
  88.           fi
  89.           return ${Color}
  90.         fi
  91.       else
  92.         j=0
  93.       fi
  94.     done
  95.   done
  96.   return 0
  97. }
  98. function weight5() {
  99.   for Color in 41 42;do
  100.     for h in 0 1 3 2;do
  101.       j=0
  102.       for i in -4 -3 -2 -1 1 2 3 4 ;do
  103.         if (( h > 1 ));then
  104.           _Color="box_$((Y_X[0]+i*$((2*h-5))))_$((Y_X[1]+2*i*$(((2*h-5)**2))))"
  105.         else
  106.           _Color="box_$((Y_X[0]+i*${h}))_$((Y_X[1]+2*i*$((! h))))"
  107.         fi
  108.         if [[ "${!_Color:-43}" == "${Color}" ]];then
  109.           if (( ++j == 4 ));then return ${Color};fi
  110.         else
  111.           j=0
  112.         fi
  113.       done
  114.     done
  115.   done
  116.   return 0
  117. }
  118. function weight4() {
  119.   for Color in 41 42;do
  120.     for h in 0 1 3 2;do
  121.       j=0;k=0
  122.       for i in -3 -2 -1 1 2 3 ;do
  123.         if (( h > 1 ));then
  124.           _Color="box_$((Y_X[0]+i*$((2*h-5))))_$((Y_X[1]+2*i*$(((2*h-5)**2))))"
  125.         else
  126.           _Color="box_$((Y_X[0]+i*${h}))_$((Y_X[1]+2*i*$((! h))))"
  127.         fi
  128.         if [[ "${!_Color:-43}" == "${Color}" ]];then
  129.           if (( ++j == 3 ));then
  130.             if (( h > 1 ));then
  131.               ((i++))
  132.               _Color="box_$((Y_X[0]+i*$((2*h-5))))_$((Y_X[1]+2*i*$(((2*h-5)**2))))"
  133.               if [[ "${!_Color}" != 4[79] ]];then let Color+=2;fi
  134.               ((i-=5))
  135.               _Color="box_$((Y_X[0]+i*$((2*h-5))))_$((Y_X[1]+2*i*$(((2*h-5)**2))))"
  136.               if [[ "${!_Color}" != 4[79] ]];then let Color+=2;fi
  137.             else
  138.               ((i++))
  139.               _Color="box_$((Y_X[0]+i*${h}))_$((Y_X[1]+2*i*$((! h))))"
  140.               if [[ "${!_Color}" != 4[79] ]];then let Color+=2;fi
  141.               ((i-=5))
  142.               _Color="box_$((Y_X[0]+i*${h}))_$((Y_X[1]+2*i*$((! h))))"
  143.               if [[ "${!_Color}" != 4[79] ]];then let Color+=2;fi
  144.             fi
  145.             [[ "${Color}" != 4[56] ]] && return ${Color}
  146.           fi
  147.         elif [[ "${!_Color:-43}" == 4[79] ]] && (( k == 0 ));then
  148.           k=1
  149.           continue
  150.         else
  151.           j=0;k=0
  152.         fi
  153.       done
  154.     done
  155.   done
  156.   return 0
  157. }

  158. function weight() {
  159.   export Color=42 _SW
  160.   (( Y_X[1] > 30 )) && _SW=$((24-Y_X[1]/2)) || _SW=$((Y_X[1]/2-6))
  161.   (( Y_X[0] > 20 )) && _SW=$(((_SW+29-Y_X[0])/2)) || _SW=$(((_SW+Y_X[0]-11)/2))
  162.   for h in 0 1 3 2;do
  163.     for i in -2 -1 1 2 ;do
  164.       if (( h > 1 ));then
  165.         _Color="box_$((Y_X[0]+i*$((2*h-5))))_$((Y_X[1]+2*i*$(((2*h-5)**2))))"
  166.       else
  167.         _Color="box_$((Y_X[0]+i*${h}))_$((Y_X[1]+2*i*$((! h))))"
  168.       fi
  169.       if [[ "${!_Color:-43}" == 42 ]];then
  170.         ((_SW+=1000))
  171.       elif [[ "${!_Color:-43}" == 4[79] ]];then
  172.         ((_SW+=100))
  173.       else
  174.         ((_SW-=300))
  175.       fi
  176.     done
  177.   done
  178. }
  179. function AI() {
  180.   export Old_Y_X=(0 0) Max=(1 0 0)
  181.   Old_Y_X=(${Y_X[@]})
  182.   for ((y=10;y<30;y++));do
  183.     for ((x=10;x<50;x+=2));do
  184.       _Color="box_${y}_${x}"
  185.       if [[ "${!_Color}" == 4[79] ]];then
  186.         Y_X=(${y} ${x})
  187.         (( Y_X[1] > 30 )) && _W=$((24-Y_X[1]/2)) || _W=$((Y_X[1]/2-6))
  188.         (( Y_X[0] > 20 )) && _W=$(((_W+29-Y_X[0])/2)) || _W=$(((_W+Y_X[0]-11)/2))
  189.         if ! $(weight5);then
  190.           if (( Max[0] < $((99999-$?*10)) ));then
  191.             Max=("$((99999-$?*10))" "${Y_X[0]}" "${Y_X[1]}")
  192.             continue
  193.           fi
  194.         elif ! $(weight4);then
  195.           _B=$?
  196.           if [[ ${_B} == 4[34] ]];then ((_B/=2));fi
  197.           if (( Max[0] < $((50000+_W-${_B}*100)) ));then
  198.             Max=("$((50000+_W-${_B}*100))" "${Y_X[0]}" "${Y_X[1]}")
  199.             continue
  200.           fi
  201.         fi
  202.       fi
  203.     done
  204.   done
  205.   Y_X=(${Old_Y_X[@]})
  206.   for h in 0 1 3 2;do
  207.     for i in -1 1 ;do
  208.       if (( h > 1 ));then
  209.         _Color="box_$((Old_Y_X[0]+i*$((2*h-5))))_$((Old_Y_X[1]+2*i*$(((2*h-5)**2))))"
  210.         Y_X=($((Old_Y_X[0]+i*$((2*h-5)))) $((Old_Y_X[1]+2*i*$(((2*h-5)**2)))))
  211.       else
  212.         _Color="box_$((Old_Y_X[0]+i*${h}))_$((Old_Y_X[1]+2*i*$((! h))))"
  213.         Y_X=($((Old_Y_X[0]+i*${h})) $((Old_Y_X[1]+2*i*$((! h)))))
  214.       fi
  215.       if [[ "${!_Color:-43}" == 4[79] ]];then
  216.         weight box_${Y_X[0]}_${Y_X[1]}
  217.         if (( Max[1] == Y_X[0] )) && (( Max[2] == Y_X[1] ));then
  218.           ((Max[0]+=_SW))
  219.         fi
  220.         if (( Max[0] < _SW ));then
  221.           Max=("${_SW}" "${Y_X[0]}" "${Y_X[1]}")
  222.         fi
  223.       fi
  224.     done
  225.   done
  226.   Y_X=("${Max[1]}" "${Max[2]}")
  227.   export box_${Y_X[0]}_${Y_X[1]}=41
  228.   echo -e "${E33}${Y_X[0]};${Y_X[1]}H${E33}41m[]${E33}49m"
  229.   Check box_${Y_X[0]}_${Y_X[1]}
  230.   if [ $? != 0 ];then Exit;fi
  231.   return 0
  232. }
  233. function Exit() {
  234.   stty echo
  235.   echo -e "${E33}35;0H${E33}49m${E33}39m${E33}?25h\n"
  236.   exit 0
  237. }

  238. # main
  239. trap 'Exit' 0 1 2 3 15 22 24
  240. stty -echo
  241. echo -e "${E33}?25l${E33}2J"
  242. create_box
  243. echo -e "${E33}${Y_X[0]};${Y_X[1]}H${E33}46m${Pie}${E33}49m"
  244. control
  245. exit 0

复制代码
人机对战那部分真的不好写,这个还算凑合能玩,方向键控制移动光标,空格键下子,落子后请耐心等待电脑落子,电脑落子后才可以继续移动光标。
没加任何禁手和其他的规则,就是看谁先连出五子,有时间在慢慢完善吧,这几天功夫也就写这么个玩意啦。

特别提示: 如果你复制网页上面的脚本不能运行,请用如下方法解决。
1、 复制网页上面的代码,保存成一个文件。 urfile
2、 去掉掉多余的空格。( sed 's/^    //' -i urfile)
3、 编辑脚本第三行 E33 变量 为 ^[[ ,注意这里面的第一个 ^[ 的输入方法是 (按住 ctrl 不放,然后按 v 在按 [ 后放开 ctrl ) 就是 ctrl-v + ctrl-[
作者: send_linux    时间: 2011-05-16 09:41
1.find . -maxdepth 1 -ls
问题2:
GNU sed 提供了-i选项,为什么有人说sed -i 并不象 ed 一样 ...
南极雨 发表于 2011-05-16 06:51



   
凑凑热闹

1:2:
因为sed -i的执行过程:先产生一个临时文件,然后把结果输出到这个文件,
最后把这个文件重 ...
yinyuemi 发表于 2011-05-16 05:11



   
沙发???

突然感觉自己水平好烂好烂,估计能答对一半就不错了……
总觉得第一个回答的人有点亏啊,有 ...
xiaopan3322 发表于 2011-05-15 23:57



   
sorry,各位,第7题题目有所变化,请大家重新考虑一下答案:)

各位答题还挺快的啊,呵呵
作者: xiaofengmanlou    时间: 2011-05-16 10:28
本帖最后由 xiaofengmanlou 于 2011-05-16 14:04 编辑

呵呵,看了遍题,发现很多不会的,
不过发现了差距,才能进步。
先把知道的回答下,参与一下,呵呵
1.find  -maxdepth 1 -mindepth 1 -type d。这样不包含当前目录本身
2.因为ed是直接在原文件上进行编辑,而sed -i是先创建临时文件,然后在临时文件上进行编辑
3.暂时没想到,呵呵
4.不一样。
5.先对test.txt文件做备份,再读取/script/scr.sedcc的内容作为sed的命令来处理test.txt(想起来,这里的-if应该要分开写吧,连在一起不能执行)
6.exec tclsh "$0" "$@" 表示用tclsh来执行当前的脚本及其参数,并替换当前的shell
7.不能。因为-f后要指定sed要读取的命令文件。如果跟着其它的参数,会被当成文件名。
假如
#!/bin/sed -f -n
运行会报这种错误:
/bin/sed: couldn't open file  -n: No such file or directory
8.$1=$1这个应该算是个伪 表达式或条件,当在BEGIN中指定了OFS时,如果在awk的程序主体中不进行任何操作,awk会认为结果没有变化,会原样输出。这里应该只要是表示真的表达式都可以。
9.
10.
作者: xiaopan3322    时间: 2011-05-16 10:49
俺再解释一下问题三吧,回答过的可以重新回答

本地是指客户端机器,CGI脚本由web服务器运行,二者在逻辑 ...
waker 发表于 2011-05-16 08:37



    哈哈,多谢版主再给一次机会,已重新回答……
作者: expert1    时间: 2011-05-16 11:22
第一题 ls -l ./* 就可以了吧?
第二个 sed的-i应该写入了临时文件里,然后再保存的。inode有变化

第三题,题目没太看明白,cgi脚本?是

第4题,是一样的,测了下

Q5:执行脚本,并且保存结果.

Q6:不会,囧

Q7:可以的吧,#后全是注释吧。

Q8,很常见的,论坛经常出现。但我不喜欢这个写法,so,也不会

Q9: 这个题要好好搞下,比较实用。站位。

Q10:这题有点难,应该是分数比重最高的
作者: xiaopan3322    时间: 2011-05-16 11:24
我自认功力不足...

不过第一题怎么没人 ls */
惟吾无为 发表于 2011-05-16 08:02



    看清题目,一级子目录
作者: 惟吾无为    时间: 2011-05-16 12:13
看清题目,一级子目录
xiaopan3322 发表于 2011-05-16 11:24

o, 理解成子目录内容了.
ls -d */
作者: justlooks    时间: 2011-05-16 12:48
本帖最后由 justlooks 于 2011-05-17 09:44 编辑

第8题
$1=$1大家都知道了,补充下$0=$0

  1. echo "aa bb"|awk '{$2="c d";}{print $2" "NF}$0=$0{print $2" "NF}'
  2. c d 2
  3. c 3
复制代码
第5题

  1. 没仔细审题,擦掉,呵呵
复制代码

作者: ziyunfei    时间: 2011-05-16 14:27
本帖最后由 ziyunfei 于 2011-08-19 10:19 编辑

慢慢答

1.     ls -Ad */


2.     ls -i 可以查看文件的inode,前后不一样.说明是sed删除并新建了文件.和vim一样


3.
  1. #!E:\Cygwin\bin\bash.exe
  2. echo -e "Content-type: text/html\n"
  3. if [[ "$REQUEST_METHOD" = "GET" ]];then
  4.         cat<<EOF
  5.         <html>
  6.         <head>
  7.         <title>发送邮件</title>
  8.         <meta http-equiv="Content-Type" content="text/html; charset=GB2312">
  9.         </head>
  10.         <body bgcolor="#9898BA" text="#000000">
  11.         <hr size="5">
  12.         <form method="post" enctype="multipart/form-data">
  13.         <label for="file"> 收件人: </label>
  14.         <input name="email" id="email" type="text“>
  15.         <label for="file"> 附件: </label>
  16.         <input name="file" id="file" type="file">
  17.         <input name="submit" value="发送" type="submit">
  18.         </form>
  19.         </body>
  20.         </html>
  21. EOF
  22. else
  23.         cat>post                           #post内容保存到post文件
  24.         email=$(awk 'NR==6{print}' post)      #得到email地址
  25.         name=$(awk -F'"' 'NR==6{print $4}' post)   # 得到上传文件名
  26.         lines=$(wc -l post|awk '{printf $1}')                #得到post文件行数
  27.         start=$(($lines-8))                                           #得到上传文件在post文件的起始行
  28.         end=$(($lines-13))                                           #得到上传文件在post文件的结束行
  29.         tail -n $start post|head -n $end > "$name"       #从post文件抽取出二进制文件
  30.         uuencode "$name" |mail -s mail $email             #发送邮件
  31.         rm post "$name"                                               #删除临时文件
  32.         echo "发送成功"
  33. fi
复制代码


4.    不一样,这个是shell本身的行为.和awk没啥关系

awk -F''  shell处理后awk只有一个参数 相当于awk -F
awk -F '' shell处理后awk有两个参数,一个是-F 一个是NULL

其他程序也一样ls'' 可以运行, ls '' 就不对了.甚至"l"s''也对

Effective AWK Programming 一书和awk manual里也专门指出了这种情况

Null strings are removed when they occur as part of a non-null command-line argument, while explicit non-null objects are kept. For example, to specify that the field separator FS should be set to the null string, use:

          awk -F "" 'program' files # correct

Don't use this:

          awk -F"" 'program' files  # wrong!

In the second case, awk will attempt to use the text of the program as the value of FS, and the first file name as the text of the program! This results in syntax errors at best, and confusing behavior at worst.




5. sed -if /script/scr.sedcc test.txt   f被当成-i的参数, 生成备份文件test.txtf /script/scr.sedcc是脚本,写明白就是 sed -if '/script/{s/r.sed//}' test.txt

6.和7题一样,关键是能添加多个参数

7.看运行方式,如果是是sed -f 脚本名 就可以,不过出题的意思应该是./脚本名,那就不行.试着解释一下

假如在-f后面添加个参数 #!/bin/sed -f -r,提示无法打开文件 -r,有人说:把-r 放 -f 前面行不行呢,答案是不行

我们不知道shell解释#!的时候到底传给了sed什么样的参数.所以我们自己写个脚本来充当sed的角色

就叫sed.sh
  1. #!/bin/bash
  2. echo "我是$0"
  3. echo "参数1=$1"
  4. echo "参数2=$2"
  5. echo "参数3=$3"
  6. echo  "完整命令为 $0 $@"
复制代码
在写一个脚本,sh.sh,用来调用我门的sed
  1. #!./sed.sh -f -r
复制代码
然后在shell里执行 ./sh.sh a.txt,模拟用sed 调用 sh.sh 来处理a.txt

sed.sh反回的结果是
  1. 我是sed.sh
  2. 参数1=-f -r
  3. 参数2=./sh.sh
  4. 参数3=a.txt
  5. 完整命令为sed.sh -f -r ./sh.sh a.txt
复制代码
也就是shell把-f -r 当成一个参数传给了sed.sh,把f和r换过来,完整命令是sed.sh -r -f ./sh.sh a.txt,好像是正确的,但其实对应的shell命令是sed.sh "-r -f" ./sh.sh a.txt,明显不对

如果 这样执行 sed.sh -f sh.sh a.txt,sed就把shebang就当成解释了,怎么写都无所谓了

8.$1=$1 是用来激活$0的重新赋值,也就是说 字段$1...和字段数NF的改变会促使awk重新计算$0的值,通常是在改变OFS后而需要输出$0时这样做

    echo "A B C D" | awk '{OFS="|";print $0;$1=$1;print $0;}'
    A B C D
    A|B|C|D
   
    即使OFS放在BEGIN里,也没有用
    echo "A B C D" | awk 'BEGIN{OFS="|"}{print $0;$1=$1;print $0;}'
    A B C D
    A|B|C|D

   $0=$0 刚好相反, 修改$0的值可以促使awk重新计算字段$1...和字段数NF的的值,通常是在改变FS后而需要输出$1...或者NF时这样做

    echo "A|B|C|D" | awk '{FS="|";print $1,NF;$0=$0;print $1,NF}'
    A|B|C|D 1
    A 4
   
    不过把修改FS放在BEGIN里,就没必要$0=$0了
    echo "A|B|C|D" | awk 'BEGIN{FS="|"}{print $1,NF;$0=$0;print $1,NF}'
    A 4
    A 4
   
其实,在awk源码中.重新计算$0的值的函数名叫rebuild_record,重构记录的意思.默认情况下.这个函数是不可能执行的.因为$0是直接读入的.$1=$1等修改字段的行为会触发awk执行这个函数
重新计算$1...的值的函数名叫reset_record,重新分割记录到字段的意思.默认情况下.这个函数只在处理完当前行,读入下一行之前执行.中途是不会执行的.$0=$0等修改记录的行为会触发awk执行这个函数
通过在源码中添加一行标记重新编译awk.可以查看awk到底什么时候运行了这两个函数.

rebuild_record
  1. echo "A B C D" | awk '{print $0;OFS="|";print "OFS=\"|\"";print $0;print "$1=$1";$1=$1;print $0;}'
  2. -----------reset_record-----------             #读入行之前,执行reset_record,把$0拆分开赋值给$1...
  3. A B C D                                         #$0为读入的值
  4. OFS="|"                                        #改变OFS
  5. A B C D                                         #没有触发rebuild_record重构$0,$0仍为读入的值.
  6. $1=$1                                           #执行$1=$1,
  7. ----------rebuild_record------------            #awk不管$1是否真的改变,执行rebuild_record.
  8. A|B|C|D                                         #$0的值成为各个字段和ORS计算出的值
复制代码
reset_record
  1. echo "A|B|C|D" | awk '{print $1,NF;print "FS=\"|\"";FS="|";print $1,NF;print "$0=$0";$0=$0;print $1,NF}'
  2. -----------reset_record-----------              #读入行之前,执行reset_record,把$0拆分开赋值给$1...
  3. A|B|C|D 1                                        #$1为刚才计算的值
  4. FS="|"                                             #改变FS
  5. A|B|C|D 1                                        #没有触发reset_record重构$1和NF,仍为第一次计算的值.
  6. $0=$0                                             #执行$0=$0
  7. -----------reset_record-----------              #awk不管$0是否真的改变,执行reset_record.
  8. A 4                                                   #$1和NF的值成为重新计算出的值
复制代码
9.
awk命令行,调用curl和grep.
  1. awk 'BEGIN{a="http://bbs.chinaunix.net/";while("curl -s "a"|grep -oP \"forum-.+-.+.html(?=. >)\""|getline b){c=c" "a""b;}while("curl -s"c"|grep -oP \"<title>.*? |(?<=版主: ).*?p>$|无权访问\""|getline d){e=gensub("<[^>]*>","","g",d);if(f==0){printf e;f++;g++}else{print ": "e;f--;split(e,h,", ");i[0];for(j in h){if(!(h[j] in i)){k++;i[h[j]]}}}}print g" : "k-2}'
复制代码
awk脚本,awk访问网络.
  1. #!/usr/bin/gawk -f
  2. BEGIN{
  3.         bbs = "http://bbs.chinaunix.net"
  4.         bbsHtml = getHtml(bbs);
  5.         while(match(bbsHtml,/forum(-[0-9]+){2}.html. >/)){
  6.                 thread = bbs"/"substr(bbsHtml,RSTART,RLENGTH-3);
  7.                 ++threadSum;
  8.                 bbsHtml = substr(bbsHtml,RSTART+RLENGTH);
  9.                 threadHtml=getHtml(thread);
  10.                 match(threadHtml,/<title>[^ ]* /);
  11.                 print "\033[32m"gensub(/<[^>]*>/,"","g",substr(threadHtml,RSTART,RLENGTH))"\033[m";
  12.                 if(match(threadHtml,/版主: [^\n]*a><.p>/)){
  13.                         bz= gensub(/<[^>]*>/,"","g",substr(threadHtml,RSTART,RLENGTH));
  14.                         print bz;
  15.                         split(substr(bz,5),sum,", ");
  16.                         for(i in sum){
  17.                                 if (!(sum[i] in bzsum))
  18.                                         bzSum[sum[i]]=1;
  19.                         }
  20.                 }
  21.                 else if(match(threadHtml,/无权访问/)){
  22.                         print "无权访问";
  23.         }
  24.         else{
  25.                 print "版主: *空缺中*";
  26.   }
  27. }
  28. print "\033[32m统计\033[m\n板块数:"threadSum" 版主数:"length(bzSum);
  29. }
  30. function getHtml(url){
  31.         host=gensub("^http://|/.*","","g",url);
  32.         path=gensub("^http://[^/]*/?","/","g",url);
  33.         socket="/inet/tcp/0/"host"/80";
  34.         print "GET "path" HTTP/1.0\r\nHost: "host"\r\n\r" |& socket;
  35.         html="";
  36.         while((socket |& getline) > 0){
  37.                 html=html$0"\n";
  38.         }
  39.         close(socket);
  40.         return html;
  41. }
复制代码
都没有考虑子版块!
作者: db2-zhang    时间: 2011-05-16 14:52
回复 2# xiaopan3322


    弱弱的问下 (echo "contents"; uuencode urfile file)

你这句什么意思???

谢谢!
作者: xiaopan3322    时间: 2011-05-16 15:15
回复  xiaopan3322


    弱弱的问下 (echo "contents"; uuencode urfile file)

你这句什么意思?? ...
db2-zhang 发表于 2011-05-16 14:52



    前半句邮件内容,后半句邮件附件
作者: lkk2003rty    时间: 2011-05-16 17:10
回复 2# xiaopan3322


    你这让别人怎么答嘛。。。。皑皑。。。。看来骗个奖品的愿望落空了。。。。。。
作者: gxj241040128    时间: 2011-05-16 17:18
本帖最后由 gxj241040128 于 2011-05-17 12:24 编辑

占座

1, du -sh ./*/  
额外算出大小

2,
sed -i
inode 发生改变,利用临时文件,并将临时文件重定向到一个新的和原文件同名的文件中
ed
inode未生改变,直接在原文件上编辑保存
sed -i修改时占用的空间是ed的两倍
作者: chenbin200818    时间: 2011-05-16 19:26
大家努力做, 我只看 学习下对同一问题各种不同的解法
作者: sosodream    时间: 2011-05-16 20:53
本帖最后由 sosodream 于 2011-05-16 22:35 编辑

问题1:
用最简洁的命令列出当前目录下的一级子目录,可以不包含隐藏目录(目录名以.开头的目录)

最简洁的,alias算不,搞个命令就是,嘿嘿
前几天群里在讨论prune,就用find写个的试试:
find * -type d -prune -print
不喜欢*
就用
find ! -path . -type d -prune -print


问题2:
GNU sed 提供了-i选项,为什么有人说sed -i 并不象 ed 一样真正的编辑文件?(提示:观察文件改变前后的inode)

以下是info sed 原文:
`-i[SUFFIX]'
`--in-place[=SUFFIX]'
     This option specifies that files are to be edited in-place.  GNU
     `sed' does this by creating a temporary file and sending output to
     this file rather than to the standard output.(1).


如下实验,原inode 661028 的文件处理完后变成了661027 ,已经不是原来inode的文件了
采用文件备份-ibk,可以看到原来的文件被rename了,创建了一个与原来名字一样的新文件做为输出结果
同时gnu也提供了-c选顶,临时文件采用copy的方式而不是rename的方式,这种方式下保留了原来的inode文件
不管有没有bk,或-c,gnu info文档自己都说了,这个-i选项的功能是通过临时文件完成的,并不是直接的在原文件上进行编辑
  1. [root@rac0 tmp]# seq 5 >sed1
  2. [root@rac0 tmp]# ls -li sed1
  3. 661028 -rw-r--r-- 1 root root 10 04-01 00:19 sed1
  4. [root@rac0 tmp]# sed -i 'n' sed1
  5. [root@rac0 tmp]# ls -li sed1   
  6. 661027 -rw-r--r-- 1 root root 10 04-01 00:19 sed1
  7. [root@rac0 tmp]# sed -ibk 'n' sed1
  8. [root@rac0 tmp]# ls -li sed1{,bk}
  9. 661028 -rw-r--r-- 1 root root 10 04-01 00:19 sed1
  10. 661027 -rw-r--r-- 1 root root 10 04-01 00:19 sed1bk
  11. [root@rac0 tmp]# sed -c -ibk2  'n' sed1
  12. [root@rac0 tmp]# ls -li sed1{,bk,bk2}  
  13. 661028 -rw-r--r-- 1 root root 10 04-01 00:21 sed1
  14. 661027 -rw-r--r-- 1 root root 10 04-01 00:19 sed1bk
  15. 661030 -rw-r--r-- 1 root root 10 04-01 00:21 sed1bk2
复制代码
-

问题3:
用shell写一个cgi脚本,提供一个简单的webmail介面,将本地的一个文件通过web服务器发送到指定的邮箱

不懂


问题4:
awk -F'' 与 awk -F '' 一样吗?

不一样,
题意是'',即设置field-separator为空,
awk的-F的选项正确的完整的格式是: -F fs
awk -F'' 经shell解析后只剩下awk -F,会把后边的一部分内容当成fs,导致命令不正确
awk -F ''  这里''在shell解析后保留了下来做为fs


问题5:
这条语句有什么作用?
sed -if /script/scr.sedcc test.txt

这题具有欺骗性,要求对-i选顶有充分的认识
-i选项是原文件直接更改,-f选顶是调用脚本文件
但-if,是-i选顶的格式,f只是一种文件备份后缀,并不是-i + -f
所以这句的结果是,备份文件(后缀f),同时执行命令“/script/scr.sedcc ”(并不是脚本)
接下来是这段命令的分析:
adress采用正则:/script/匹配"script"字符串
command部分为scr.sedcc,这个,s是最常用的替换命令,但格式是s///,而因为s///的格式是请允许用其他字符替代/的,这里便是用字符‘c‘替代/
所以这个替换命令的意思是:当行里匹配“script“字符串时,删除掉行里的r.sed字符串,其中.是元字符

结论:这段命令的做用:文件备份(后缀f)之后+原文件将删除匹配“script“字符串的行里的r.sed字符串,其中.是元字符,一行只删一次
  1. [root@rac_2 ~]# echo scriptrased| sed  /script/scr.sedcc   
  2. script
复制代码
另,若要-i+-f,需分开:sed -i -f /script/scr.sedcc test.txt


问题6:
#!/bin/sh
# the next line restarts using tclsh \
exec tclsh "$0" "$@"

是如何执行的?与"#!/usr/local/bin/tclsh"相比,它有什么优点?


不懂tclsh
exec的作用是执行命令替代当前进程环境
从上边的命令格式来看,至少有一点好处是:不用指定绝对路径,嘿嘿


问题7:
#!/bin/sed -f"  shebang 后可有其它字符吗?为什么?

apue里解释器文件的起始行形式是:
#! pathname [optional-argment]
在!与pathname之前可以任意空格(不超过exec系统函数最大长度就是了)~~~
man bash里也只提到上边的格式
至于其他字符。。。没用过,不晓得能不能。


问题8:
GNU awk的$1=$1到底有什么作用?$0=$0呢?

$1=$1
这里赋值操作从右到左解析,右操作数引用$1没啥好讲的,左操作数引用触发了域赋值
域赋值的一个隐含动作,是为引起$0的重构的,即在下次$0引用时,重构为$1OFS$2OFS....,OFS为输出分隔符

$0=$0
同样赋值操作从右到左解析,右操作数引用$0,这里要注意是否引发重构,右操作数$0对记录重新赋值,
记录赋值的一个隐含动作,就是重新分割记录,即在下次$n(n>0)引用或NF引用时,重新按FS进行解析

讲得比较泛,具体的,可以看刚发的一篇blog:http://blog.csdn.net/sosodream/archive/2011/05/16/6425192.aspx



问题9:
写一个shell脚本,输出CU现有的版面和相应版主,并统计有多少个版面及多少个版主。

echo :CU现有的版面和相应版主,并统计有多少个版面及多少个版主。



问题10:
人机五子棋。原始规则(无禁手),最好加上标准规则,三手交换(即黑下第二手之后白可以提出交换),五手两打,黑三三禁手,黑四四禁手,黑长连禁手(超过5个子相连),逢五无禁手。白无禁手,长连也算胜。关键在于人机对下。

浮云,飘啊飘
作者: xiaopan3322    时间: 2011-05-16 21:34
回复 25# sosodream


    向楼上的第五题的精彩回答致敬……真的……
    看来大家都想当然了……
    这条命令确实是对test.txt的文件的一个备份,备份后的结果是test.txtf
作者: ziyunfei    时间: 2011-05-16 21:41
回复  sosodream


    向楼上的第五题的精彩回答致敬……真的……
    看来大家都想当然了……
     ...
xiaopan3322 发表于 2011-05-16 21:34

为啥不向我致敬
这道题一看就有问题,不可能那么简单
作者: xiaopan3322    时间: 2011-05-16 21:49
回复 27# ziyunfei


    我也向你致敬……
    主要可能因为我白天看你的答案的时候,你还没更新上去吧,就直接看到后面的了,要不然,我肯定先向你致敬啊……
作者: sosodream    时间: 2011-05-16 22:22
本帖最后由 sosodream 于 2011-05-16 22:28 编辑

回复 26# xiaopan3322


    多谢,{:2_172:}

刚才回帖的时候其实是有疑问的,刚去吃了个晚饭,休息了下,回头又看到了没说完整的,刚补充了下
其实第八道题答题答得更全了,就在链接里,特意写了个blog,发过来怕补骂灌水呵,比较长
作者: send_linux    时间: 2011-05-16 22:41
回复  xiaopan3322


    多谢,

刚才回帖的时候其实是有疑问的,刚去吃了个晚饭,休息了 ...
sosodream 发表于 2011-05-16 22:22



    呵呵,够敬业啊,这么晚了才吃饭,辛苦!
作者: blackold    时间: 2011-05-16 22:56
汗,还有很多不懂。
作者: blackold    时间: 2011-05-16 23:06
发现好多Sheller都没有认真审题,就像输入了一个rm xx命令,也不检查,直接就Enter了,爽啊。
作者: xiaopan3322    时间: 2011-05-16 23:37
回复 32# blackold


    好爽……
作者: chenbin200818    时间: 2011-05-17 01:48
回复 7# 南极雨


    没看多少,扫了一眼

第一个答案错误,
关于awk -F 也错误  你将空作分隔符试试 -F"" -F ""
作者: chenyx    时间: 2011-05-17 08:51
一个也不懂
看各位的答案学习吧
作者: yuhuohu    时间: 2011-05-17 09:08
这贴才是真正的高手云集
作者: codylin    时间: 2011-05-17 09:10
高手。。。。
作者: waker    时间: 2011-05-17 09:12
这又不是闭卷考试,要善用搜索与测试啊
作者: codylin    时间: 2011-05-17 09:15
我自认功力不足...

高手。。。。
作者: shplpy    时间: 2011-05-17 09:17
回复 21# xiaopan3322


    问题9:
写一个shell脚本,输出CU现有的版面和相应版主,并统计有多少个版面及多少个版主。

echo :CU现有的版面和相应版主,并统计有多少个版面及多少个版主。


这道题满分~
作者: 南极雨    时间: 2011-05-17 09:20
本帖最后由 南极雨 于 2011-05-17 09:24 编辑

回复 34# chenbin200818



擦...真丢人...见笑了..
作者: surpass_li    时间: 2011-05-17 09:26
本帖最后由 surpass_li 于 2011-05-17 10:57 编辑

问题1:
用最简洁的命令列出当前目录下的一级子目录,可以不包含隐藏目录(目录名以.开头的目录)
  1. ll -d */


  2. ls -d */
复制代码
问题2:
GNU sed 提供了-i选项,为什么有人说sed -i 并不象 ed 一样真正的编辑文件?(提示:观察文件改变前后的inode)
  1. ed 是一个交互式的通用的文本编辑器, sed 则主要用在 scripts 中进行非交互式的文件修改.
  2. ed 一个文件时, 我们可以自由的在文件的各行间跳来跳去, 而 sed 则是对文件顺序地扫描一遍且仅一遍.
  3. sed 打开文件仅一次. 非交互的 ed 打开文件也仅一次, 但在交互式的 ed 中, 每次 w 应该会导致一次 close()+open()
  4. 当然, ed 也可以像 sed 那样进行非交互式的文件修改. 既然 ed 可以在文件里来回跳转, 一定程度上要比 sed 更灵活一些. 说到使用变量, ed 跟 sed 是一样的, 都得通过 $var 的方式.
复制代码
问题3:
用shell写一个cgi脚本,提供一个简单的webmail介面,将本地的一个文件通过web服务器发送到指定的邮箱

问题4:
awk -F'' 与 awk -F '' 一样吗?
  1. 不一样,前面的语法有误。
复制代码
问题5:
这条语句有什么作用?
sed -if /script/scr.sedcc test.txt
  1. 先对test.txt文件做备份为test.txtf,同时执行命令“/script/scr.sedcc ” 将文件test.txt中的内容删除匹配“script“字符串的行里的r.sed字符串,一行只删一次
复制代码
问题6:
#!/bin/sh
# the next line restarts using tclsh \
exec tclsh "$0" "$@"

是如何执行的?与"#!/usr/local/bin/tclsh"相比,它有什么优点?
  1. 表示用tclsh来执行当前的脚本及其参数,并替换当前的shell
复制代码
问题7:
#!/bin/sed -f"  shebang 后可有其它字符吗?为什么?
  1. 不可以。因为-f后要指定sed要读取的命令文件。如果跟着其它的参数,会被当成文件名
复制代码
问题8:
GNU awk的$1=$1到底有什么作用?$0=$0呢?
  1. $1=$1为了让OFS生效。$0=$0不能。
复制代码
问题9:
写一个shell脚本,输出CU现有的版面和相应版主,并统计有多少个版面及多少个版主。


问题10:
人机五子棋。原始规则(无禁手),最好加上标准规则,三手交换(即黑下第二手之后白可以提出交换),五手两打,黑三三禁手,黑四四禁手,黑长连禁手(超过5个子相连),逢五无禁手。白无禁手,长连也算胜。关键在于人机对下。
作者: 南极雨    时间: 2011-05-17 09:35
老大,加一道题吧,: 以最简单的方式提取IP地址 ,...我特想知道,每次匹配都要写半天...
作者: yifangyou    时间: 2011-05-17 09:46
本帖最后由 yifangyou 于 2011-05-24 00:00 编辑

问题1:
用最简洁的命令列出当前目录下的一级子目录,可以不包含隐藏目录(目录名以.开头的目录)

答:
  1. ls -F|grep "/"
复制代码
问题2:
GNU sed 提供了-i选项,为什么有人说sed -i 并不象 ed 一样真正的编辑文件?(提示:观察文件改变前后的inode)

答:sed -i会先把编辑好的内容生成到临时文件,然后把原文件删除,再把临时文件改为原文件名,这个文件和原文件已经不是同一个文件
而ed只是在原文件上修改,并不移动或者删除原文件
sed -i 对于经常被读的文件或者已经被打开的文件非常不安全


问题3:
用shell写一个cgi脚本,提供一个简单的webmail介面,将本地的一个文件通过web服务器发送到指定的邮箱

答:我写了两个页面,支持多个收件人,支持发送人定义,支持中文和发送图片或者文本,或者二进制文件
webmail.sh:
  1. #!/bin/bash

  2. echo "Content-type: text/html"
  3. echo ""

  4. echo '<html>'
  5. echo '<head>'
  6. echo '<meta http-equiv="Content-Type" content="text/html;charset=UTF-8">'
  7. echo '<title>send mail</title>'
  8. echo '</head>'
  9. echo '<body>'
  10. echo '<form action="sendmail.sh" method="post"  ENCTYPE="multipart/form-data">';
  11. echo '<table>';
  12. echo '<tr><td width="200px">send from:</td><td><input type="text" name="mail_from" value="" style="width:300px"></td></tr>';
  13. echo '<tr><td>send to:</td><td><input type="text" name="mail_to" value="" style="width:300px">(separate by ;)</td></tr>';
  14. echo '<tr><td>title</td><td><input type="text" name="mail_title" value="" style="width:300px"></td></tr>';
  15. echo '<tr><td>mail body</td><td><textarea name="mail_body" style="width:400px;height:300px"></textarea></td></tr>';
  16. echo '<tr><td>Attach file</td><td><input type="file" name="mail_attachment" value=""></td></tr>';
  17. echo '<tr><td>&nbsp;</td><td><input type="submit" value="send"></td></tr>';
  18. echo '</table>'
  19. echo '</form>';
  20. echo '</body>'
  21. echo '</html>'
  22. exit 0
复制代码
sendmail.sh的代码:
  1. #!/bin/bash
  2. tmp_path=/tmp
  3. uuid=`cat /proc/sys/kernel/random/uuid`
  4. uuid_file=$tmp_path/$uuid;
  5. Muttrc_file=$tmp_path/Muttrc

  6. echo "Content-type: text/html"
  7. echo ""

  8. echo '<html>'
  9. echo '<head>'
  10. echo '<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">'
  11. echo '<title>Environment Variables</title>'
  12. echo '</head>'
  13. echo '<body>'
  14. #把post的数据写入文件
  15. cat - > $uuid_file
  16. #读取文件分隔行
  17. break_line=`head -1 $uuid_file`""
  18. line_no=0;
  19. #按照分隔行分隔
  20. while read  field
  21. do
  22.         let line_no=$line_no+1;
  23.         if [ "$field" == "$break_line" ]
  24.         then
  25.                 break_line_no="$break_line_no $line_no"
  26.         fi
  27. done < $uuid_file
  28. break_line_no="$break_line_no $line_no"
  29. break_line_nos=($(echo "$break_line_no"))
  30. #获取发送者的邮箱
  31. let data_line_end=${break_line_nos[1]}-1
  32. let data_line_total=$data_line_end-${break_line_nos[0]}-2;
  33. mail_from=`head -$data_line_end $uuid_file|tail -$data_line_total|tr "\r\n" " "`


  34. #获取收件人的邮箱
  35. let data_line_end=${break_line_nos[2]}-1
  36. let data_line_total=$data_line_end-${break_line_nos[1]}-2;
  37. mail_to=`head -$data_line_end $uuid_file|tail -$data_line_total|tr ";" " "`


  38. #获取标题
  39. let data_line_end=${break_line_nos[3]}-1
  40. let data_line_total=$data_line_end-${break_line_nos[2]}-2;
  41. title=`head -$data_line_end $uuid_file|tail -$data_line_total`

  42. #获取邮件正文
  43. body_file=$uuid_file".body"
  44. let data_line_end=${break_line_nos[4]}-1
  45. let data_line_total=$data_line_end-${break_line_nos[3]}-2;
  46. head -$data_line_end $uuid_file|tail -$data_line_total > $body_file

  47. #获取附件
  48. attach_file=""
  49. let head_line_start=${break_line_nos[4]}+1
  50. attach_name=`head -$head_line_start $uuid_file|tail -1|sed 's/.*filename="\(.*\)"\s*$/\1/'`;
  51. if [[ $attach_name != "" ]]
  52. then
  53.         let data_line_end=${break_line_nos[5]}-1
  54.         let data_line_total=$data_line_end-${break_line_nos[4]}-3;
  55.         attach_file=$tmp_path/$attach_name
  56.         head -$data_line_end $uuid_file|tail -$data_line_total > $attach_file
  57.         echo $attach_file
  58. fi

  59. #设置发送者邮箱
  60. echo "set from=\"$mail_from\"" > $Muttrc_file
  61. echo "set use_from=yes" >> $Muttrc_file
  62. echo 'set envelope_from="yes"' >> $Muttrc_file
  63. #设置发送者名称
  64. echo "set realname=\"$mail_from\"" >> $Muttrc_file
  65. #设置编码
  66. echo "set charset=\"UTF-8\"" >> $Muttrc_file

  67. if [ "$attach_file" = "" ]
  68. then
  69.         #发送无附件邮件
  70.         mutt -s "$title" -F $Muttrc_file $mail_to < $body_file
  71. else
  72.   #发送有附件邮件
  73.         mutt -s "$title" -F $Muttrc_file $mail_to -a $attach_file < $body_file
  74. fi
  75. if [ $? ]
  76. then
  77.         echo '<script>alert("send mail success");location="webmail.sh"</script>'
  78. else
  79.         echo '<script>alert("send mail fail");location="webmail.sh"</script>'
  80. fi
  81. #rm -f $body_file $attach_file $uuid_file
  82. echo '</body>'
  83. echo '</html>'

  84. exit 0;
复制代码




问题4:
awk -F'' 与 awk -F '' 一样吗?

答:awk -F''是错的,awk -F ''声明分隔符为空格


问题5:
这条语句有什么作用?
sed -if /script/scr.sedcc test.txt

答:没有用处,这句话等同于sed -i "" /script/scr.sedcc
如下面的测试结果:
  1. [root@localhost scp]# cat /script/scr.sedcc
  2. 1d
  3. s/echo/ppp/g
  4. s/password/333333/g
  5. [root@localhost scp]# sed -if /script/scr.sedcc  test.txt
  6. [root@localhost scp]# cat /script/scr.sedcc
  7. 1d
  8. s/echo/ppp/g
  9. s/password/333333/g
  10. [root@localhost scp]# sed -if "" /script/scr.sedcc  test.txt
  11. [root@localhost scp]# cat /script/scr.sedcc
  12. 1d
  13. s/echo/ppp/g
  14. s/password/333333/g
复制代码
而sed -i -f /script/scr.sedcc  test.txt才有用处
sed -i -f /script/scr.sedcc  test.txt实现对test.txt执行/script/scr.sedcc里的语句后把输出的内容写到临时文件,用临时文件把test.txt覆盖,
  1. [root@localhost scp]# cat /script/scr.sedcc
  2. 1d
  3. s/echo/ppp/g
  4. s/password/333333/g
  5. [root@localhost scp]# sed -i -f /script/scr.sedcc  test.txt
  6. [root@localhost scp]# cat test.txt
  7. ppp 11111
  8. sd 333333
  9. sscript

  10. [root@localhost scp]# cat /script/scr.sedcc
  11. 1d
  12. s/echo/ppp/g
  13. s/password/333333/g
复制代码
问题6:
#!/bin/sh
# the next line restarts using tclsh \
exec tclsh "$0" "$@"

是如何执行的?与"#!/usr/local/bin/tclsh"相比,它有什么优点?

答:执行过程是:
1.这个脚本被sh执行
2.在sh里1,2行是注释,因此不执行
3.sh 执行到第三行后,exec语句导致shell停止处理而启动 tclsh来重新处理整个脚本
启动tclsh,把这个脚本本身给传进去($0),再把别的参数($@)一起传进去
4.当 tclsh启动时,因为第二行的反斜线导致第三行被作为第二行注释的一部分,它把所有三行都作为注释对待。

用#!/usr/local/bin/tclsh的缺点
1.当tclsh的安装路径不是/usr/local/bin/的话,需要修改这个脚本的"#!/usr/local/bin/tclsh"
2.许多UNIX系统不允许 #!行超出30个字符的长度,所以要确定tclsh可执行文件能被用短文件名访问。

#!/bin/sh
# the next line restarts using tclsh \
exec tclsh "$0" "$@"
的好处:
1.tclsh的执行路径不需要写死是某个路径下的tclsh,这样tclsh就可以随心安装到那里都可以
2.解决了许多UNIX系统不允许 #!行超出30个字符的长度的文件。
3.这种方法在tclsh自身也是shell脚本时仍可运行

问题7:#!/bin/sed -f"  shebang 后可有其它字符吗?为什么?
答:可以有空格或者不可见字符,但是不能有其他可见字符
因为sed的对于-f的定义如下:
sed [选项] -f sed脚本文件 输入文件

其中sed脚本文件就是shebang所在的文件
若是输入了一个可见字符a :
#!/bin/sed -f a
那就变成了
#!/bin/sed -f a shebang所在的文件 被操作的文件
这时a变为script文件
而shebang所在的文件变为被操作文件

而我们实际要这样用
#!/bin/sed -f shebang所在的文件 被操作的文件


问题8:
GNU awk的$1=$1到底有什么作用?$0=$0呢?

答:$1=$1是用于去除第一列为0的行或者是空行
  1. cat a.txt
  2. a b c

  3. 0 1 2
  4. 3 4 5

  5. awk '{if($1=$1)print $0}' a.txt
  6. a b c
  7. 3 4 5
复制代码
$0=$0是用于去除空行
  1. cat a.txt
  2. a b c

  3. 0 1 2
  4. 3 4 5

  5. awk '{if($1=$1)print $0}' a.txt
  6. a b c
  7. 0 1 2
  8. 3 4 5
复制代码
问题9:
写一个shell脚本,输出CU现有的版面和相应版主,并统计有多少个版面及多少个版主。

答:
  1. #!/bin/bash
  2. #清空临时文件
  3. > webmaster.txt
  4. > forum.txt
  5. #下载首页
  6. wget http://bbs.chinaunix.net -O index.html -o g.log
  7. if [ "$?" -ne "0" ]
  8. then
  9.         echo "get index.html fail"
  10.         exit 1;
  11. fi

  12. #解析首页里各个版的url
  13. cat index.html|tr "\r\n" " "|sed 's/<\//\n/g'| sed 's/.*<a\s*href\s*=\s*"\(forum\-[0-9]*\-[0-9]*.html\)".*>/\n1b5fd1544f2e9dff4956b84ba4ff60f5 \1 /g' |tr "<" "\n"|grep 1b5fd1544f2e9dff4956b84ba4ff60f5|awk '{if($3=$3)print $2,$3}'|uniq > forum.txt

  14. printf "+%30s+%80s+\n" "" "" |tr " " "-"
  15. cat forum.txt|while read line
  16. do
  17.         forum_url=`echo "$line"|awk '{print $1}'`
  18.         forum=`echo "$line"|awk '{print $2}'`;
  19.         #获取各个版的html
  20.         wget http://bbs.chinaunix.net/$forum_url -O index.html -o g.log
  21.         if [ "$?" -eq "0" ]
  22.         then
  23.                 #解析出各个版的版主
  24.                 cat index.html|tr "\r\n" " "|sed 's/<\/p>/\n/g'|sed 's/<p id="modedby">/\n1b5fd1544f2e9dff4956b84ba4ff60f5 /g'|grep 1b5fd1544f2e9dff4956b84ba4ff60f5|sed 's/<\//"\n/g'| sed 's/<a .*>/\nbb512805cc402f58c2188678b59148eb "/g' |grep bb512805cc402f58c2188678b59148eb|awk -v fu="$forum_url" '{if($2=$2)print fu,$2}'|uniq >>  webmaster.txt
  25.         fi
  26.         webmasters=`grep "$forum_url" webmaster.txt |awk '{print $2}'|tr "\n" ","`
  27.         #输出版和版主
  28.         printf "|%30s|%80s|\n" "$forum" "$webmasters"
  29. done
  30. printf "+%30s+%80s+\n" "" "" |tr " " "-"
  31. forum_total=`wc -l forum.txt`
  32. webmaster_total=`uniq -f 1 webmaster.txt |wc -l`
  33. #输出统计结果
  34. echo "forum total:$forum_total,webmaster total:$webmaster_total"
复制代码


作者: jhinux    时间: 2011-05-17 17:45
Shell版块是ChinaUnix社区内讨论比较热烈的技术版块之一。之前我们已经成功举办了PHP、C/C++和Perl的编程大 ...
send_linux 发表于 2011-05-15 23:51

二等奖:5名,,获奖者为最先正确完成8道试题的七名用户,赠送特别定制版ChinaUnix商务衬衫。

    恕我愚钝,这个到底是五还是七?
作者: send_linux    时间: 2011-05-17 18:47
二等奖:5名,,获奖者为最先正确完成8道试题的七名用户,赠送特别定制版ChinaUnix商务衬衫。

    恕我 ...
jhinux 发表于 2011-05-17 17:45



    五名,sorry,我去修改一下。
作者: blackold    时间: 2011-05-17 21:36
回复 45# nuclearxin


    误导也是一种测试啊
作者: meego2012    时间: 2011-05-18 18:39


有机会,我也试一下,先占个位置,呵呵
作者: Kabie    时间: 2011-05-18 18:52
...第十题稍微变态了些。。。
作者: send_linux    时间: 2011-05-18 22:55


居然有人反映,置顶了看不到了,真是奇怪啊!
作者: angle4    时间: 2011-05-18 22:56
哇, 已经开始好几天了, 今天才在sina微薄看到
作者: hq8318    时间: 2011-05-19 02:06
哇, 已经开始好几天了, 今天才在sina微薄看到
angle4 发表于 2011-05-18 22:56



    我也是昨天才发现,这比赛还是越迟提交,越吃亏的。
作者: send_linux    时间: 2011-05-19 09:51
我也是昨天才发现,这比赛还是越迟提交,越吃亏的。
hq8318 发表于 2011-05-19 02:06



    呵呵

重在参与嘛
作者: shplpy    时间: 2011-05-19 12:03

作者: angle4    时间: 2011-05-19 12:43
本帖最后由 angle4 于 2011-05-19 13:02 编辑

发帖编辑, 格式老乱, 咋整?
作者: angle4    时间: 2011-05-19 12:50
本帖最后由 angle4 于 2011-05-20 15:25 编辑

1. 用最简洁的命令列出当前目录下的一级子目录,可以不包含隐藏目录(目录名以.开头的目录)

  1. # 显示当前目录下的子目录
  2. echo "当前目录下的子目录"
  3. ls -l | grep -E '^d' | awk '{print $8}'

  4. # 显示当前目录下的子目录, 包含隐藏目录
  5. echo "当前目录下的子目录, 包含隐藏目录"
  6. ls -la | grep -E '^d' | awk '{print $8}' | grep -Ev '^\.$|^\.\.
  7. # 下面的也可以, 没法现那个更简洁
  8. # find . -maxdepth 1 -type d ! -regex '^\.
复制代码
2. GNU sed 提供了-i选项,为什么有人说sed -i 并不象 ed 一样真正的编辑文件?(提示:观察文件改变前后的inode)

  1. 的确, sed -i 是先用sed处理完,再rename操作的。
  2. 从 strace sed -i 's/1/x/g' out 就可以清楚的看到。

  3. 看inode也很清楚,
  4. $ cal > out
  5. $ ls -i out
  6. 1541258 out
  7. $ sed -i 's/2/x/g' out && ls -i out
  8. 1541255 out
复制代码
3. 用shell写一个cgi脚本,提供一个简单的webmail介面,将本地的一个文件通过web服务器发送到指定的邮箱

  1. #!/bin/bash

  2. # 用shell写一个cgi脚本,提供一个简单的webmail介面,将本地的一个文件通过web服务器发送到指定的邮箱

  3. echo Content-type: text/html
  4. echo ""

  5. email=$(echo "$QUERY_STRING" | sed -n 's/^.*email=\([^&]*\).*$/\1/p' | sed "s/%40/@/g")
  6. file_name=$(echo "$QUERY_STRING" | sed -n 's/^.*file_name=\([^&]*\).*$/\1/p' | sed "s/%20/ /g")

  7. /bin/cat << EOF
  8. <html>
  9. <head>
  10.   <title>webmail cgi</title>
  11. </head>
  12. <body>
  13. EOF
  14. if [ -z $email  -o -z $file_name ]; then
  15.         /bin/cat << EOF
  16.   <form method="get">
  17.     Email: <input type="text" name="email"/><br />
  18.     File : <input type="file" name="file_name"/><br />
  19.     <input type="submit" value="submit"/><br />
  20.   </form>
  21. EOF
  22. else
  23.         mail -s $file_name $email < $file_name \
  24.                 && echo "Done.</br>" \
  25.                 || echo "Error ..."
  26.         #echo "email: $email</br>"
  27.         #echo "file_name: $file_name</br>"
  28. fi

  29. /bin/cat << EOF
  30. </body>
  31. </html>
  32. EOF
复制代码
4. awk -F'' 与 awk -F '' 一样吗?

  1. 不一样,
  2. awk -F field-separator # awk -F ':'
  3. awk -Ffield-separator  # awk -F:

  4. 所以, awk -F '' 结果是每个字符都是一个字段; 而, awk -F'' 是有语法错误的.
复制代码
5. 这条语句有什么作用? sed -if /script/scr.sedcc test.txt

  1. -if 将test.txt备份为 test.txtf
  2. /script/scr.sedcc 会做为sed命令执行, 结果就是在test.txt中查找包含script的行,一行一行的查找,找到后,将该行的r.sed替换为空,每行只替换第一次找到的.
  3. sed 中s是字符串替换,c在这是分割符,然后就很明显了.
复制代码
6. #!/bin/sh
# the next line restarts using tclsh \
exec tclsh "$0" "$@"
是如何执行的?与"#!/usr/local/bin/tclsh"相比,它有什么优点?

  1. 执行过程:
  2.   sh首先处理这个脚本, 忽略第二行(注释), 然后,执行第三行.
  3.   exec 使shell停止执行,并且开始运行tclsh, tclsh重新处理这个脚本,它把这三行都作为注释(因为第一行末有个\, 所以第三行也是注释).
  4.   这个脚本后面的内容有tclsh解释、执行.

  5. 优点:
  6.   1. 不用考虑tclsh的绝对路径,只要PATH中可以找到就行, shebang中可执行文件必须写绝对路径,而不同的发行版tclsh的默认安装路径可能不同.
  7.   2. 可以避免shebang过长, 有些早期发行版对shebang长度有限制.
  8.   3. shebang中必须是二进制的可执行文件,而不能是一个shell脚本, 而,有时为了处理多架构和多个操作系统,tclsh很可能是一个shell脚本.
  9.   4. 把tclsh做成一个脚本,有助于使用不同版本的tclsh.
复制代码
7. #!/bin/sed -f"  shebang 后可有其它字符吗?为什么?

  1. 可以, 如: #!/bin/sed -fa.sed, a.sed 将作为 -f 的参数. -f后的所有字符串将作为一个参数, 所以, #!/bin/sed -fa.sed -fb.sed将报错,除非你当前目录有个文件名为"a.sed -fb.sed".
复制代码
8. GNU awk的$1=$1到底有什么作用?$0=$0呢?

  1. # from awk manpage
  2. # Assigning a value to an existing field causes the whole record to  be  rebuilt  when  $0  is  referenced.
  3. # Similarly, assigning a value to $0 causes the record to be resplit, creating new values for the fields.

  4. # sample code
  5. $ echo 'a b c' | awk '{print $0; $1=$1;OFS=":"; FS=":"; print $0; print $1}'
  6. a b c
  7. a:b:c
  8. a

  9. $ echo 'a b c' | awk '{print $0; $0=$0;OFS=":"; FS=":"; print $0; print $1}'
  10. a b c
  11. a b c
  12. a

  13. 从上面的例子可以看出:
  14. $1=$1导致整个记录($0)重新创建,字段也会根据FS的值重新分割.
  15. $0=$0只会使字段根据FS的值重新分割.
复制代码

作者: angle4    时间: 2011-05-19 13:07
[i=s] 本帖最后由 angle4 于 2011-05-19 18:02 编辑 [/i]

9. 写一个shell脚本,输出CU现有的版面和相应版主,并统计有多少个版面及多少个版主。

ChinaUnix共有74个版块
ChinaUnix共有165个版主[code]
#!/bin/bash

# root url
RURL="http://bbs.chinaunix.net"

# 获取版块
# in: 如果无参数调用,获取首页的所有版块;
#     如果提供一个参数调用, 返回该版块内的子版块
# out: 输出获取到的版块名
function get_forums()
{
    if [ -z $1 ]; then
        curl $RURL -o- 2>/dev/null | grep -Eo 'forum[^"]+\.html' | sort -u
    else
        curl $RURL/$1 -o- 2>/dev/null | grep -Eo 'forum[^"]+\.html' | \
            grep -v "$1" | sort -u
    fi

}

# 获取指定版块的版块名
# in: 版块, 如: forum-216-1.html
# out: 输出该版块的名字
function get_forum_name()
{
    curl $RURL/$1 -o- 2>/dev/null | grep forumheader -A 1 | \
        iconv -f GBK -t UTF-8 | \
        cut -d'>' -f2 | cut -d '<' -f1
}

# 获取指定版块的所有版主
# in: 版块, 如: forum-216-1.html
# out: 输出该版块的所有版主
function get_moderators()
{
    test -z $1 && echo "usage $0 <forum-123-1.html" && exit
    curl $RURL/$1 -o- 2>/dev/null | \
        grep modedby -A 1 | iconv -f GBK -t UTF-8 | \
        tr ',' '\n' | \
        cut -d'>' -f2 | cut -d'<' -f1 | \
        grep -Ev '^
}

function main()
{
    my_forums=$(get_forums)
    for x in $my_forums; do
        get_forum_name $x
        echo -e "\t$(get_moderators $x | xargs)"
        my_sub_forums=$(get_forums $x)
        for sub_x in $my_fub_forums; do
            get_forum_name $sub_x
            echo -e "\t$(get_moderators $sub_x | xargs)"
        done
    done
}

TMPFILE=$(mktemp)
main | tee $TMPFILE

# 版块数
forum_num=$(grep -Ev '^[[:space:]]' $TMPFILE | grep -Ev '^ | sort -u | wc -l)
echo "ChinaUnix共有$forum_num个版块"

# 版主数
moderator_num=$(grep -E '^[[:space:]]' $TMPFILE | tr -d '\t' | tr ' ' '\n' | grep -Ev '^ | sort -u | wc -l)
echo "ChinaUnix共有$moderator_num个版主"

rm -f $TMPFILE

[/code]
作者: angle4    时间: 2011-05-19 13:08
本帖最后由 angle4 于 2011-05-19 13:12 编辑

10. 人机五子棋。原始规则(无禁手),最好加上标准规则,三手交换(即黑下第二手之后白可以提出交换),五手两打,黑三三禁手,黑四四禁手,黑长连禁手(超过5个子相连),逢五无禁手。白无禁手,长连也算胜。关键在于人机对下。
[code][/code]
作者: angle4    时间: 2011-05-19 13:13
先占个位, 慢慢写
作者: jiang5feng    时间: 2011-05-19 15:16
支持,占座先
作者: hmchzb19    时间: 2011-05-19 17:20
这题看了,我连回答的勇气都没了
作者: sosodream    时间: 2011-05-19 17:28
本帖最后由 sosodream 于 2011-05-21 02:57 编辑

闲着无聊,继续答题
问题:GNU sed 提供了-i选项,为什么有人说sed -i 并不象 ed 一样真正的编辑文件?(提示:观察文件改变前后的inode)

注意审题的话,这题是二个文件编辑器的比较,
也有可能是提示的误导,这题大都知道答-i 是用临时文件的机制,
但这道题如果不通过说明ed 的模式,再做sed -i 与ed 比较,
怎么看都不算完整

======sed的基本模式======
sed的模式是基于二个space的cycle的“流编辑器”,流的特点:有进有出,一次一行,不能回退即不能重复读
sed -i的编辑模式:将原文件rename成新文件名(tmpfile),以tmpfile为输入,一行一行处理后,输出保存到文件(与原文件同名)

======ed===========
ed,这个以前没用过,刚找男人问来的,今天闲着又翻了下源码看了下
ed的模式就是:scrach_file + line_buffer + command动作,
scrach_file是ed一开始调用标准tempfile函数创建的,tempfile在/tmp下以“程序名.随机后缀”为名读写方式创建一个临时文件,并在程序时退出时删除
  1. [root@rac0 tmp]# file ed.b3db5b
  2. ed.b3db5b: ASCII text, with no line terminators
复制代码
临时文件保存的是纯数据(无行结束符),而line_buffer有点像“元数据”,是内存中的一个结构链表,一个节点一个行信息,保存各行起始位移和长度
ed file命令下会在运行ed时一开始便将文件全部读取,数据去除换行符后存放到临时文件,行信息保存在line_buffer里,然后进行相关操作
ed里的命令w将根据buffer里的记录信息将数据全部保存回文件


========比较=========
所以sed -i 跟ed是二种不同的文件编辑模式,

从执行模式来区别:
sed -i是将文件存重命名为临时文件后做为输入流,按行读取进行cycle处理,输出保存到与原文件同名的新空文件里。
后者是将文件一次全部读取,然后将数据存放到内存buffer和临时文件里,处理完后再通过w命令回写入文件

从编辑对像来区别:
sed跟ed的单元动作都是以行数据为对象的,也程为行操作。不同在于
sed -i  的处理过程中,保存在内存里二个buffer的是部分行数据,可能是一行或多行数据
ed 处理过程中,保存在内存里的是所有的行信息。


从inode来区别:用inode来区分二者的编辑模式,也是一种方法
由于sed把原文件rename了,结果的文件inode已经非原来的inode了
这种情况下,可以加入sed -c操作,保留文件的inode不变了
-c是gnu sed 提供的,其他unix下的sed冒似不一定有(悲具的unix)

======================
这个题目出得有点让人郁闷,什么叫“真正的编辑文件”
真正的编辑文件,比如c程序(不带缓存的文件I/O)里OPEN文件后,直接根据描述符,对文件进行读写
而sed -i 实际上是流处理,ed在处理过程中实际上是在编辑“临时文件”
事实上个人觉得sed -i 跟ed都不是“真正的编辑”文件
作者: gyh9711    时间: 2011-05-20 10:25
做了很多年unix系统管理员,写过不少维护脚本,不过一看这些题,发现原来编写脚本,只是个菜鸟
作者: rollingpig    时间: 2011-05-20 14:14
ed 其实也有临时文件,可以去/var/tmp底下看看

$ ls
00_000_TLD.txt  01_000_TLD.txt  a.out           support.out     upgrade.tar
-- ed .. in another session
$ ls
00_000_TLD.txt  01_000_TLD.txt  a.out           eaAAAIDa49D     support.out     upgrade.tar
作者: angle4    时间: 2011-05-20 15:27
那我要再看下ed去, ,,, 答题时看想sed了,以为ed就是相反的
作者: 网中淫    时间: 2011-05-20 18:40
shell版平时都是新手的乐园,这个帖子好多老人出现了。。
作者: renxiao2003    时间: 2011-05-22 21:36
我知道的时候就这么多人答完题了。看来我没有希望了。呵呵。抽空答一下。
作者: njuytwc    时间: 2011-05-23 01:54
新手也参与一个,貌似只会回答第一个问题,我也给出不同的答案
问题1:
用最简洁的命令列出当前目录下的一级子目录,可以不包含隐藏目录(目录名以.开头的目录)
答:
ls -l|grep ^d   或者
ll|grep ^d
作者: beginner-bj    时间: 2011-05-23 08:07
晕,我怎么才看到这个帖子
作者: beginner-bj    时间: 2011-05-23 08:13
看了下题,只会做一半,剩下一半要查资料且第10题不会。
作者: 首天    时间: 2011-05-23 11:27
echo */  这个命令用法不错,学习了
作者: send_linux    时间: 2011-05-23 14:41
看了下题,只会做一半,剩下一半要查资料且第10题不会。
beginner-bj 发表于 2011-05-23 08:13



    来的及,来得及老大,嘿嘿

我们的那个aix挑战赛也请多去看看
作者: ooooldman    时间: 2011-05-23 17:25

  我来试着回答一下把
1,
  1. ls  -d  */
复制代码
  1. ls -l  |grep  "^d"
复制代码
2,ed 只是纯粹的读写文件,sed 会将文件读入读出内存。
3,html语法不会
4,没试过,不过应该是一样的
5,sed 会用/script/scr.sedcc 修改 test.txt文件。
作者: ooooldman    时间: 2011-05-23 17:28
6,exec 会派生一个子进程来执行
作者: hq8318    时间: 2011-05-24 02:40
回复 70# 首天


    命令确实好,试过也行,但总是不怎么理解。
作者: woai122    时间: 2011-05-24 09:22
再也不会小瞧shell了,自己还是个初学者
作者: 首天    时间: 2011-05-25 11:17
本帖最后由 首天 于 2011-05-26 13:39 编辑
回复  首天


    命令确实好,试过也行,但总是不怎么理解。
hq8318 发表于 2011-05-24 02:40

呵呵
个人的理解echo是一个屏显命令,“*” 是匹配任意字符,“/”是匹配文件夹,"*/"的组合则匹配当前目录下面的所有非隐藏目录
如 echo * 则显示所有不以点开头的文件  #2011.5.26 更新
    echo .* 则显示所有以点开头的文件 #2011.5.26 更新
作者: hq8318    时间: 2011-05-26 03:41
呵呵
个人的理解echo是一个屏显命令,“*” 是匹配任意字符,“/”是匹配文件夹,"*/"的组合则匹配当前目 ...
首天 发表于 2011-05-25 11:17



    谢谢你的解释。以前只知echo用来显示字符,现在看来若是通配符,它显示文件、目录。想显示含有通配符的字符,则要加上引号。
作者: beginner-bj    时间: 2011-05-26 11:15
回复 71# send_linux


    不高称老大啊。这些题我看前面的人都回答得比我好,我就不掺和了。
今年的aix挑战赛开始了吗?我去AIXCHINA看看。
作者: 惟吾无为    时间: 2011-05-26 13:13
呵呵
个人的理解echo是一个屏显命令,“*” 是匹配任意字符,“/”是匹配文件夹,"*/"的组合则匹配当前目 ...
首天 发表于 2011-05-25 11:17

echo .* 只显示以点开头的文件.
{ echo .* ; echo * } == ls -a

这是bash的文件名扩展功能.
作者: 首天    时间: 2011-05-26 13:36
echo .* 只显示以点开头的文件.
{ echo .* ; echo * } == ls -a

这是bash的文件名扩展功能.
惟吾无为 发表于 2011-05-26 13:13

谢谢纠正,我上面说错了
作者: demornov    时间: 2011-05-26 22:22
最后一题如果用shell的话肯定慢得很,大家可以看附件里的规则,或这里
[quote]http://www.itiyu.com/project/chess/331/rule.htm
[/quote],如果我没算错的话,所有可能的禁手共有165种,每种禁手要判断的点都在10个以上,而且禁手在棋盘中的位置不定,简单点,算160个,那么每一步的计算量就是:165*10*160=264000,即使算法再好,用shell也快不起来
gobang.zip (27.82 KB, 下载次数: 62)
作者: shplpy    时间: 2011-05-26 22:42
占个位置
作者: r12340031    时间: 2011-05-27 13:01
1.# ls -d */
只会一个
作者: liqix    时间: 2011-05-27 17:29
只为瞻仰大牛而来。火速围观
作者: hq8318    时间: 2011-05-29 15:14
本帖最后由 hq8318 于 2011-05-31 22:49 编辑

先做几题,其它再补上。

问题1:
用最简洁的命令列出当前目录下的一级子目录,可以不包含隐藏目录(目录名以.开头的目录)

1) ls -l | grep ^d
2) echo */
3) ls -F | grep /
4)ls -l |grep ^d |awk '{printf $8"\t"}'
5)ls -l | awk '/^d/{print $8}'
大家给出了很多种做法,总结一下大概有以上5种,1~3会在目录名后有个“/”;4~5长些,无“/”,命令中'$8'看情况,有时是'$9'。
增加简略通用的一种:
6)ls -l | awk '/^d/{print $NF}'

问题2:
GNU sed 提供了-i选项,为什么有人说sed -i 并不象 ed 一样真正的编辑文件?(提示:观察文件改变前后的inode)

根据测试,sed -i处理文件,inode有变化,而ed不会,所以sed -i并不是编辑原文件的。

问题3:
用shell写一个cgi脚本,提供一个简单的webmail介面,将本地的一个文件通过web服务器发送到指定的邮箱


问题4:
awk -F'' 与 awk -F '' 一样吗?

不一样。awk -F''会被shell当作awk -F,故报错;awk -F '' 被认为分隔符是'',作用成为:无分隔符,输出第一个字符。

问题5:
这条语句有什么作用?
sed -if /script/scr.sedcc test.txt

  “-if”与“-i -f”不同,“-if”是插入并备份。语句可分成两部分,“sed -i /script/”匹配"script"字符串,插入后面的内容;“scr.sedcc”s是替换命令,后面c是分隔符,相当于s/r.sed//,“.”是元字符--除换行外任意字符。
  整条语句相当于“sed -if /script/s/r.sed// test.txt”,备份文件,加上f后缀:test.txtf;查找有"script"字符串的一行,将“r.sed”删除。

问题6:
#!/bin/sh
# the next line restarts using tclsh \
exec tclsh "$0" "$@"
是如何执行的?与"#!/usr/local/bin/tclsh"相比,它有什么优点?

第一行说明用sh解析执行脚本;第二行是注释,跳过;第三行指明用tclsh重新解析脚本:第二行末有“\”, 所以三行都是注释,变成脚本后面的内容由tclsh解析。

问题7:
#!/bin/sed -f"  shebang 后可有其它字符吗?为什么?

不可以,有其它字符,会当成文件名。

问题8:
GNU awk的$1=$1到底有什么作用?$0=$0呢?

测试如下:(awk的分隔符缺省是空格)
sh-3.00# v='1 2 3:a:b:c'
sh-3.00# echo $v|awk '{FS=":";print $1,NF}'
1 3
sh-3.00# echo $v|awk '{FS=":";$0=$0;print $1,NF}'
1 2 3 4
sh-3.00# echo $v|awk '{OFS=":";print $0,NF}'
1 2 3:a:b:c:3
sh-3.00# echo $v|awk '{OFS=":";$1=$1;print $0,NF}'
1:2:3:a:b:c:3
可以看到,
$1=$1使输出分隔符OFS起作用,而NF不变;$0=$0则对分隔符FS起作用,并且NF改变。

问题9:
写一个shell脚本,输出CU现有的版面和相应版主,并统计有多少个版面及多少个版主。


问题10:
人机五子棋。原始规则(无禁手),最好加上标准规则,三手交换(即黑下第二手之后白可以提出交换),五手两打,黑三三禁手,黑四四禁手,黑长连禁手(超过5个子相连),逢五无禁手。白无禁手,长连也算胜。关键在于人机对下。

作者: send_linux    时间: 2011-05-30 00:12
先做几题,其它再补上。

问题1:
用最简洁的命令列出当前目录下的一级子目录,可以不包含隐藏目录(目录 ...
hq8318 发表于 2011-05-29 15:14



   

继续加油!
作者: send_linux    时间: 2011-05-30 00:12
最后一题如果用shell的话肯定慢得很,大家可以看附件里的规则,或这里
,如果我没算错的话,所有可能 ...
demornov 发表于 2011-05-26 22:22 [/quote]



作者: blackold    时间: 2011-05-30 11:27
不要简单地回答对或错,最好解释一下为什么。
作者: newyue    时间: 2011-05-30 14:17
我就不参与了,跟大家学习学习~~第一层都没练成~
作者: hitsubunnu    时间: 2011-05-30 14:58
waker
Shell_HAT
cjaizss
blackold

每个大赛评委团成员都应发个第十题的答案 要不没资格做评审
作者: wgmaster    时间: 2011-05-30 15:47
N久没搞了,先占个坑。
作者: send_linux    时间: 2011-05-31 09:12
N久没搞了,先占个坑。
wgmaster 发表于 2011-05-30 15:47



    ha,记得到时候来答题啊,时间剩下不多了,呵呵
作者: hq_333    时间: 2011-05-31 19:35
简单做一做,志在参与。

1.
echo */|sed 's/\/ / /g' 将“/ ”用正则"/\/ / /"替换。
2.
sed -i对文件的inode有变化,而ed是真正的编辑文件。
3.
4.
不,awk -F''被认为缺少参数,awk -F '' 将认为分隔符是''。
5.
sed -if /script/scr.sedcc test.txt => sed -if /script/s/r.sed// test.txt ,先把原文件更名备份(test.txt->test.txtf),再"sed -i /script/s/r.sed//":查找有script的行,把r.sed替换为空。
6.
执行:sh载入,行2忽略,行3由tclsh重新载入脚本、解析。
优点:1、文件名可超过30个字符;
      2、tclsh可在任何目录(path有tclsh)
      3、tclsh 可以是一脚本,更灵活。
7.
不可,其它字符会被当作文件名。
8.
$1=$1令OFS生效,NF不变;$0=$0令FS生效,NF改变。
作者: bjruntest    时间: 2011-06-01 18:48
zhichi l
作者: 职业民工    时间: 2011-06-02 13:03
厉害,不错不错!蛮经典的题目!
作者: h200952709    时间: 2011-06-08 14:38
竟然发现有我会的题{:3_182:}
作者: hq8318    时间: 2011-06-10 17:49
来的及,来得及老大,嘿嘿

我们的那个aix挑战赛也请多去看看
send_linux 发表于 2011-05-23 14:41



    那个aix挑战赛,什么时候评选啊?奖品诱人,可惜人气不足,总不能因为少人参与,而不评选,不发奖品吧。
作者: send_linux    时间: 2011-06-10 18:06
那个aix挑战赛,什么时候评选啊?奖品诱人,可惜人气不足,总不能因为少人参与,而不评选,不发奖 ...
hq8318 发表于 2011-06-10 17:49



    不会的,因为暂时还没有完全确认好,好了一定会公布结果的,呵呵,可能时间会适当延长的:(
作者: crazyhadoop    时间: 2011-06-13 10:09
太强憾了~膜拜,我也要努力学习shell
作者: joe9i0    时间: 2011-06-20 19:56
回复 10# xinyv


    输入 ^[[ 不用那么麻烦呀, 可以用 \e[ 代替的.




欢迎光临 Chinaunix (http://bbs.chinaunix.net/) Powered by Discuz! X3.2