shell学习之-程序的流程控制(1)

时间:2022-10-17 05:37:40
shell编程学习
2
3 1, shell程序的流程控制
4
5 **条件测试语句if then fi
6 全部的基本形式为:
7
8 if xxxx; then
9 xxx
10 elif xxx; then
11 xxx
12 elsif xxx; then
13 xxx
14 else
15 xxx
16 fi
17
18 条件语句有两种编写形式:
19 *if xxx
20 then
21 xxx
22 fi
23
24 *if xxx; then
25 xxx
26 fi
27
28 (1)简单的if then fi
29
30 *******
31 if [ "10" < "12" ]; then
32 echo "yes"
33 fi
34 *******
35 注意:这里的if和[间有一空格,参数和[间也有一个空格。而;和then间可以没有空格,表示继续执行后面的语句;
36
37 (2)变量测试
38 具体的变量测试的语法和比较的关键字,可以使用 man test 进行查询
39
40 *****
41 #!/bin/sh
42 #testvar.sh
43
44 echo "please input you name :"
45 read NAME
46
47 if [ "$NAME" = "" ]; then
48 echo "you name is null"
49 elif [ "$NAME" = "hover" ]; then
50 echo "haha, It's me"
51 else
52 echo "You name is ${NAME}, welcome!"
53 fi
54
55 exit
56 *****
57 小结:当变量中含有空格或TAB时,必须用引号引起来。所以如果对变量进行测试,一般是要用引号引起来的。
58
59 (3)对执行语句进行测试
60
61 *****
62 #!/bin/sh
63 #test-express.sh
64
65 echo "iput a string:"
66 read STR
67
68 if echo "$STR" | grep 'hover' &>/dev/null
69 then
70 echo "haha, I am here, I am ${STR}"
71 else
72 echo "I am not here"
73 fi
74
75 exit
76 *****
77 小结:
78 *这里测试的表达是可以多种多样,而且可以测试与和或的表达式,具体的语法可以man test 进行查看。
79 *在进行语句的测试时,如果需要避免错误信息或输出信息,需要用到重定向,具体的专门有专题讲解。
80
81 (4)测试传递的参数
82
83 *****
84 #!/bin/sh
85 #test-invar.sh
86
87 #test paramter which user input
88
89 printusage()
90 {
91 echo "usage : $0 [start|stop|restart]"
92 }
93
94 if [ $# -ne 2 ]; then
95 printusage
96 elif [ "$1" = "" ]; then
97 printusage
98 elif [ "$1" = "start" ]; then
99 echo "start $0"
100 elif [ "$1" = "stop" ]; then
101 echo "stop $0"
102 elif [ "$1" = "restart" ]; then
103 echo "restart $0"
104 else
105 printusage
106 fi
107
108 exit
109 *****
110 小结:和C一样,shell编程中也可以传递参数。其中,$0 $1 ..$n 分别表示参数的第0个第1个第n个值。$#表示参数的个数。
111
112 (5) : null参数
113 : 表示true , 也表示什么都不做
114
115 *****
116 if [ -z "`ls $1`" ]
117 then :
118 else
119 echo "not zero"
120 fi
121
122 *****
123
124 (6) 多个if 的流程控制
125
126 *****
127 #!/bin/sh
128 #mut-if.sh
129
130 #测试使用多个if的情况
131 if [ -z $HH ]; then
132 echo "do you want to set HH"
133 echo "enter [y/n]"
134 read Y_N
135
136 #now set HH
137 if [ "$Y_N" = "y" ] || [ "$Y_N" = "Y" ]
138 then
139 echo "please input value :"
140 read HH
141 if [ -z $HH ]
142 then : #HH is null do nothing
143 else
144 echo "now HH=${HH}"
145 fi
146 else
147 HH=hover
148 echo "no, then use default: $HH"
149 fi
150
151 else
152 HH=hover
153 echo "default value is $HH"
154 fi
155
156 echo "last HH=${HH}"
157 unset HH
158 echo "HH unseted, test finished"
159 exit
160
161 *****
162
163 总结: if流程基本上就这么多,具体的用法要根据实际情况进行灵活应用。
164
165
166 2,case 语句
167 case 一种多开关语句,在测试具有多种值的变量时比if语句灵活。
168 使用模式为:
169 case 值 in
170 模式1)
171 命令1
172 ;;
173 模式2)
174 命令2
175 ;;
176 *)
177 命令n
178 esac
179
180 case先取值(记住取值的后面必须要有一个in),然后依次进行匹配模式n :
181 如果有一个模式匹配,则执行相应的命令n,遇到;;结束,退出case语句。
182 如果都不匹配,可以使用*来捕获该值,并从新接受输入。
183
184 (1)简单的case应用
185 *****
186 #!/bin/sh
187 #test-case.sh
188
189 echo "input a number: "
190 read NUM
191
192 case $NUM in
193 1) echo "111"
194 ;;
195 2) echo "22"
196 ;;
197 3) echo "33"
198 ;;
199 *)
200 echo "no match"
201 esac
202 *****
203
204 小结:这里只简单的使用了数字来进行测试,发散一下,如果是单词或多个单词,又该如何呢?
205
206 (2)模式和多模式匹配的应用
207
208 *****
209 #!/bin/sh
210 #test-case1.sh
211
212 echo "Do you want to continue? [y/n|yes/no]"
213 read ANS
214
215 case $ANS in
216 y|Y|yes|Yes|YES)
217 echo "you can continue"
218 ;;
219 n|no|No|NO)
220 echo "you stop"
221 ;;
222 *)
223 echo "your input is wrong"
224
225 esac
226
227 *****
228
229 小结:在匹配多模式时,模式可以以|链结表示“或”的意思。这样就可以进行多模式的匹配了。
由于是单模式的匹配,所以不存在“与”的模式。
230
231 (3)测试命令参数
232
233 *****
234 #!/bin/sh
235 #test-case1.sh
236
237 if [ "$#" -ne "1" ]; then
238 echo "please input one of [start|stop|restart]"
239 exit 1
240 fi
241
242 VAR=$1
243 case $VAR in
244 start)
245 echo "sart ... `basename $0`"
246 ;;
247 stop)
248 echo "stop ... `basename $0`"
249 ;;
250 restart)
251 echo "restar ... `basename $0`"
252 ;;
253 *)
254 echo "input is wrong"
255 ;;
256 esac
257
258 *****
259
260 小结:先要对用户是否出入了命令参数进行检查,然后把第一个参数赋值给一个变量,然后进行处理。
261
262 3,for 循环语句
263 ==============
264
265 for 循环语句的基本形式为:
266 for arg [list]
267 do
268 命令
269 done
270
271
272 for arg [list]; do
273 命令
274 ...
275 done
276
277 注意:在循环的每次执行中,arg将顺序的存取list中列出的变量.
278 list中的参数允许包含通配符.
279
280 (1)简单的for程序
281
282 *****
283 #!/bin/sh
284 #test-for.sh
285
286 #测试for语句
287
288 for loop in 1 2 3 4 5 6
289 do
290 echo $loop
291 done
292
293 *****
294
295
296 *****
297 #!/bin/sh
298 #test-for1.sh
299
300 ll="a b c d e"
301 for loop in $ll
302 # for loop in "$ll"
303 do
304 echo $loop
305 done
306
307 *****
308
309 注意:in $ll 和 in "$ll"的区别。前面是简单的替换,没有屏蔽空格,而后面才是完整的变量使用。
310
311 (2)在[list]中使用通配符
312
313 *****
314 #!/bin/sh
315 #test-for2.sh
316
317 #list all file in local dir
318
319 for t_dir in *
320 do
321 echo "$t_dir"
322 done
323
324 echo "=====list file whose name begin with j or s in local dir====="
325 for t_dir1 in [ts]*
326 do
327 echo "$t_dir1"
328 done
329
330 *****
331
332 (3)使用命令替换[list]
333
334 ######
335 #!/bin/bash
336 # for-loopcmd.sh: 带[list]的for循环
337 #+ [list]是由命令替换产生的.
338
339 NUMBERS="9 7 3 8 37.53"
340
341 for number in `echo $NUMBERS` # for number in 9 7 3 8 37.53
342 do
343 echo -n "$number "
344 done
345
346 echo
347 exit 0
348 #####
349
350
351 (4)在命令行使用参数
352 如果in [list]的值为空,那么默认的是使用参数传给for循环。
353
354 #####
355 for ll
356 do
357 echo $ll
358 done
359 #####
360
361
362 4 until 循环结构(用的不多)
363 ===================
364 这个结构在循环的顶部判断条件,并且如果条件一直为false那就一直循环下去.(与while基本格式相反)
365
366 until 条件
367 命令1
368 ...
369 done
370 注意:条件可以为任意测试条件,测试发生在循环末尾。循环至少执行一次。
371
372 #########
373 #!/bin/sh
374 #test-until.sh
375
376 #判断root是否已经登陆
377
378 IS_ROOT=`who | grep root`
379 until [ "$IS_ROOT" ]
380 do
381 sleep 2
382 done
383 echo "root have went in"
384
385 exit
386
387 #########
388
389 5,while 循环结构(比较常用)
390 这种结构在循环的开头判断条件是否满足,如果条件一直满足,那就一直循环下去(0为退出码).
与for循环的区别是,这种结构适合用在循环次数未知的情况下. 其基本的格式如下:
391
392 while [condition]
393 do
394 command...
395 done
396
397 ######
398
399 while [condition]; do
400 command...
401 done
402
403 和for循环一样,如果想把do和条件放到同一行上还是需要一个";".
404
405 (1)简单的while循环
406
407 #########
408 #!/bin/sh
409 #test-while.sh
410
411
412 N=0
413 while [ $N -lt 5 ]
414 do
415 N=$( expr $N + 1 ) #或者N=`expr $N + 1`
416 echo $N
417 done
418
419 #########
420
421 (2)利用while读取文件
422
423 #######
424 #2 : read file using while
425 while read LINE
426 do
427 echo $LINE
428 done < t1.sh
429
430 #######
431
432 注意:在读取文件时,输入的格式最好使用以上的形式,而不要使用
433 cat filename | while read LINE
434 这样可能会出错。
435
436 也可以用多个变量来保存多个域的项目
437 ff.txt
438 1 h
439 2 hh
440 3 hhh
441 4 hhhh
442
443 #####
444
445 while read N NAME
446 do
447 echo $N $NAME
448 done < ff.txt
449
450 #####
451
452 注意:这里使用的默认的IFS,如果要处理用:分隔的项目,可以把IFS设置成:然后再进行处理。
453 如:
454 IFS_BACK=$IFS
455 IFS=:
456 ***
457 ***进行一些操作
458 IFS=$IFS_BACK
459
460
461 (3)统计文件中的记录
462
463 文件ff的内容如下:
464 h1 23
465 h2 34
466 h1 45
467 h2 56
468 h1 87
469 要求计算h1的总和?
470
471 ######
472 #计算文件中的统计项目的总和
473
474 RFILE=ff
475 TOTAL=0
476 CA_NAME="$1"
477
478 echo "$#"
479 if [ "$#" -ne "1" ]; then
480 echo "usage : $0 <name>"
481 exit 1
482 fi
483
484 while read NAME NUM
485 do
486 if [ "$NAME" = "$CA_NAME" ]; then
487 TOTAL=`expr $TOTAL + $NUM`
488 fi
489 done < $RFILE
490
491 if [ "$TOTAL" -eq "0" ]; then
492 echo "$CA_NAME is not exit or $RFILE is worng"
493 else
494 echo "$CA_NAME total is $TOTAL"
495 fi
496
497 ######
498
499 (4)在读文件时忽略特定行
500
501 #remove the commet line
502 re_com()
503 {
504 while read line
505 do
506 case $line in
507 /#*|ITEM|"/n");; #这里注意
508 *)
509 echo "data: $line"
510 ;;
511 esac
512 done < data.txt
513 }
514
515 6,利用break和continue控制程序的流程
516
517 (1)跳出case
518
519 #!/bin/sh
520 #t_break.sh
521
522 #在死循环中如何跳出
523 while :
524 do
525 echo "please input a number: "
526 read NS
527 case $NS in
528 1|2|3|4|5)
529 echo "great! you entered a number between 1 and 5"
530 ;;
531 *)
532 echo "wrong, good bye!"
533 break;
534 ;;
535 esac
536 done
537
538 而continue 语句和c语言中的continue语句有相同的用法。
539
540 到此流程控制的基本用法就告一段落,而要灵活使用它们需要在实践中练习,练习,再练习。
541
542 下面利用这些东西可以写一个简单的菜单,来给用户提供该系统的运行情况的信息。
就是一个系统状态汇报系统。包括系统的内存使用情况,CPU使用情况,磁盘空间的使用情况,
有哪用户已经登陆到该系统上,系统中有哪些进程,开启了哪些服务,该使用系统及其内核的版本.
第一步只需要把该系统做成单一的程序,而第二部可以使用crond服务作成实时监控定期报警的方式。
543
544
545 7, 如何注释掉一段sh程序
546
547 1)在vi中使用命令: %s/^/#/g
548 2)在要注释的段前后加:
549 <<BLOCK
550 ...
551 BLOCK