闲话几句:不是特别喜欢按部就班地跟着教科书学东西,觉得刚开始一点都不了解的时候,需要看一点书,了解一些之后,就要多看实际的例子,通过实践、例子来把东西学明白。
接着前面(3)中的quiz的例子,把其中拍代码时不时很明白的几个点,抠出来琢磨下。
1: #!/bin/bash
2: # a quiz program
3:
4: set -o xtrace
5:
6: #============================
7: function initialize ()
8: {
9: trap 'summarize ; exit 0' INT
10: num_ques=0
11: num_correct=0
12: first_time=true
13: cd ${QUIZDIR=./quiz} || exit 2
14: }
15:
16: #===========================
17: function choose_subj ()
18: {
19: subjects=($(ls))
20: PS3="Choose a subject for the quiz from the proceding list:"
21: select Subject in ${subjects[*]};do
22: if [[ -z "$Subject" ]];then
23: echo "No subject chosen. Bye." >&2
24: exit 1
25: fi
26: echo $Subject
27: return 0
28: done
29: }
30:
31: #===========================
32: function exchange ()
33: {
34: temp_value=${questions[$1]}
35: questions[$1]=${questions[$2]}
36: questions[$2]=$temp_value
37: }
38:
39: #===========================
40: function scramble ()
41: {
42: typeset -i index quescount
43: questions=($(ls))
44: questcount=${#questions[*]}
45: ((index=questcount-1))
46: while [[ $index -gt 0 ]];do
47: ((target=RANDOM%index))
48: exchange $target $index
49: ((index -= 1))
50: done
51: }
52:
53: #===========================
54: function ask ()
55: {
56: exec 3<$1
57: read -u3 ques || exit 2
58: read -u3 num_opts || exit 2
59:
60: index=0
61: choices=()
62: while (( index < num_opts )) ; do
63: read -u3 next_choice || exit 2
64: choices=("${choices[@]}" "$next_choice")
65: ((index+=1))
66: done
67: read -u3 correct_answer || exit 2
68: exec 3<&-
69:
70: if [[ $first_time = true ]];then
71: first_time=false
72: echo -e "You may process the interrupt key at any time to quit.\n"
73: fi
74:
75: PS3=$ques" "
76:
77: select answer in "${choices[@]}";do
78: if [[ -z "$answer" ]];then
79: echo "Not a valid choice. Please choose again"
80: elif [[ "$answer" = "$correct_answer" ]];then
81: echo "Correct!"
82: return 1
83: else
84: echo "No, the answer is $correct_answer."
85: return 0
86: fi
87: done
88: }
89:
90: #================================
91: function summarize ()
92: {
93: echo
94: if (( num_ques == 0));then
95: echo "You did not answer any questions"
96: exit 0
97: fi
98:
99: (( percent=num_correct*100/num_ques ))
100: echo "You answered $num_correct questions correctly, out of \
101: $num_ques total questions."
102: echo "Your score is $percent percent."
103: }
104:
105: #=================================
106: # Main program
107: initialize
108:
109: subject=$(choose_subj)
110: [[ $? -eq 0 ]] || exit 2
111:
112: cd $subject || exit 2
113: echo
114: scramble
115:
116: for ques in ${questions[*]};do
117: ask $ques
118: result=$?
119: (( num_ques=num_ques+1 ))
120: if [[ $result == 1 ]];then
121: ((num_correct+=1))
122: fi
123: echo
124: sleep ${QUIZDELAY:=1}
125: done
126:
127: summarize
128: exit 0
129:
130: set +o xtrace
a) cd ${QUIZDIR:=./quiz} || exit 2
这里对QUIZDIR赋值,:= 表示给变量赋默认值
这里展开说,是shell对未赋值变量的值的处理方式:A,变量使用默认值 B,使用默认值并将其赋给变量 C,显示错误
> ":-" 使用默认值
:- 使用一个默认的值来代替空的没有赋值的变量,不能改变变量本来的值,只是在这句话执行的时候,让变量使用这个默认值
${name:-default} 如果name为空或没有赋值,就使用扩展值default,并把扩展值替换name的内容;否则使用name的内容
> ":=" 赋默认值
与":-"比较地看,:= 改变了变量的默认值。
${name:=default}
> :? 显示错误信息
当通过设置默认的变量值并不能给脚本中某些变量提供一个合理的值,如果变量为空或未赋值,:? 会显示出错误信息并中止脚本的执行,同时返回退出码 1
${name:? message}
如果message中包含空格,则要用""括起来
${var:?"variable not set!"}
另外:
" : " 冒号通常给命令行上其后的符号赋值而不会执行后面的命令,如果没有没有,shell会赋值并试图执行来自赋值语句的命令
eg. : ${TEMPDIR:=/tmp}
b) subjects=($(ls))
从执行结果来说,这条命令是 先执行ls,然后将ls的结果作为一个数组,赋值给subjects
c) select Subject in ${subjects[*]};
利用select选择器,遍历subjects数组中的内容,subjects[index]返回对应数组中对应index的值,如果index为*,则返回整个数组
d) temp_value=${questions[$1]} ; questions[$1]=${questions[$2]} ; questions[$2]=$temp_value
常见的swap函数,要说的是对函数传入参数的使用,传入两个参数,直接用$1,$2引用即可
e) questcount=${#questions[*]}
前面${subjects[*]}得到一个数组,这里在数组名前面加#,得到是整个数组的大小。
f) exec 3<$1 ; read -u3 ques || exit 2
这里可以看到输入重定向后,使用重定向的文件描述符读取内容的方法 read后加选项 –u3
g) choices=("${choices[@]}" "$next_choice")
这条放在while循环语句里面,不断向数组中增加内容。
这里说的是${arrName[*]} 与${arrName[@]}的区别
在没有""包围的情况下,两者都是一样的,返回整个数组中的元素
在有""包围的情况下,"${arrName[*]}"将所有元素,作为一个元素来返回,如"a,b,c,d",而"${arrName[@]}",将元素独立返回,即返回的是一个数组,如"a","b","c","d"
---------------------写到这里,发现前面有些点,前天刚刚看过,55555,温故而知新啊-------------------
> grep
(global regular expression print) 在一个或多个文件中搜索是否包含某给定字符串,列出搜索结果所在的行
grep [options] pattern [file-list] pattern可以是简单的字符串,也可以是正则表达式
[options]
1、主选项
-E
将pattern解释为可扩展的正则表达式,功能同egrep
-F
将pattern解释为固定的正则表达式,功能同fgrep
-G
将pattern解释为基本的正则表达式,默认选项
2、其他选项
-c 返回匹配行个数
-C n 对每个匹配,显示n行上下文
-f patternfile 读取patternfile,文件中每行都是一个pattern,从输入中查找匹配每个模式的行
-h 搜索多个文件时,隐藏每行开始的文件名
-I(大写i) 模式中的小写字母可以匹配大写字母,忽略大小写
-l(小写L) 仅显示匹配的文件名,每个文件名只显示一次
-m n 设定最大显示行数n,即对所有匹配,只显示n行,之后的不再显示
-n 在匹配结果前显示行号
-q 不发送任何内容,只显示退出码
-r 递归地扫描目录下的文件,此时file-list中含目录
-s 静默,如果file-list中文件不存在或不可读,不显示错误信息
-v 反向匹配,显示所有不匹配的行
-w 全字匹配,模式必须与整个字匹配
-x 整行匹配,模式必须匹配整行
grep 匹配成功,退出状态为0;没找到,状态为1;文件不可读或语法错误,状态为2
pattern 可以用单引号 '' 括起来,以防模式串中出现特殊字符
eg.
创建文件夹shfiles,如果创建成功,就将当前目录下所有扩展名为sh的文件拷贝到shfiles目录下:
(mkdir shfiles) && (cp `ls|grep '.sh$'` shfiles)
>test
这里主要是总结下tes计算表达式值的时候用到的一些选项:
Options:
-n string string长度大于零则为true
-z string string长度等于零则为true
string1=string2 两串相等为true
string1!=string2 两串不等为true
-d filename filename是否为目录
-e filename filename是否存在
-f filename filename是否为普通文件
-r filename filename是否可读
-s filename filename存在且包含信息
-w filename filename是否可写
-x filename filename是否可执行
-a AND
-o OR