概述
承接上篇,继续介绍一下另一个循环语句select,还有脚本中函数的相关内容,分为三个部分:
1、select语句的介绍和效果演示
2、脚本函数详解
3、函数效果举例
第一章 select语句的介绍和效果演示
1、select 循环与菜单格式
select VAR in LIST;do
循环体命令
done
select 循环主要用于创建菜单,按数字顺序排列的菜单项将显示在标准错误上,并显示 PS3 提示符,等待用户输入
用户输入菜单列表中的某个数字,执行相应的命令
用户输入被保存在内置变量 REPLY 中
2、select 与 case
select 是个无限循环,因此要记住用 break 命令退出循环,或用 exit 命令终止脚本。也可以按 ctrl+c退出循环
select 经常和 case 联合使用
与 for 循环类似,可以省略 in list , 此时使用位置参量
3、selcet应用举例
4、补充:脚本执行时几种执行方式的区别
.和source来执行脚本与bash 和给脚本执行权限执行的区别:
. 和source执行脚本时:没有开子进程执行脚本,相当于直接在shell里面运行脚本里面的语句,故运行完脚本,脚本里面的变量在shell里依然有效
bash或执行权限执行脚本:开了个子进程执行脚本,故脚本里面定义的变量,无法在shell里面继续生效
第二章 脚本中函数详解
1、函数的基本概念
函数function是由若干条shell命令组成的语句块,实现代码重用和模块化编程。
它与shell程序形式上是相似的,不同的是它不是一个单独的进程,不能独立运行,而是shell程序的一部分。
注意:定义函数的代码段不会自动执行,在调用时才执行
2、函数和shell程序比较相似,区别在于:
Shell程序在子Shell中运行
而Shell函数在当前Shell中运行。因此在当前Shell中,函数可以对shell中变量进行修改
函数在脚本中,相当于在脚本中插入了一段代码,所以函数并不是在脚本的shell中又开一个子shell执行函数,而是跟脚本shell在同一个shell中
3、函数的定义:
语法一:
function FUNCTION_NAME {
函数体
}
语法二:
FUNCTION_NAME() {
函数体
}
函数的定义位置:
可在交互式环境下定义函数
可将函数放在脚本文件中作为它的一部分
可放在只包含函数的单独文件中
4、函数的调用
在代码中给定函数名即可,函数名出现的任何位置,在代码执行时,都会被自动替换为函数代码
函数的生命周期:被调用时创建,返回时终止
可以将经常使用的函数存入函数文件,然后将函数文件载入shell。文件名可任意选取,但最好与相关任务有某种联系。例如: functions.main,一旦函数文件载入shell,就可以在命令行或脚本中调用函数。可以使用set命令查看所有定义的函数,其输出列表包括已经载入shell的所有函数。若要改动函数,首先用unset命令从shell中删除函数。改动完毕后,再重新载入此文件
载入文件的方式:. FILENAME或source FILENAME
5、函数的返回值
函数有两种返回值:
函数的执行结果返回值:
<1> 使用echo或printf命令进行输出
<2> 函数体中调用命令的输出结果
函数的退出状态码:
<1> 默认取决于函数中执行的最后一条命令的退出状态码
<2> 自定义退出状态码, 其格式为:
return 从函数中返回,用最后状态命令决定返回值
return 0 无错误返回。
return 1-255 有错误返回
return其功能与脚本中exit的功能类似,在函数运行的任何地方,出现return即代表函数终止,即便return的位置不是最后一行,也会退出整个函数,功能与脚本的exit一样,脚本中一旦遇到exit,就退出脚本的运行
6、删除函数
unset命令完成此功能.命令格式为:unset FUNCTION_NAME
7、函数中的参数
函数可以接受参数:
传递参数给函数:调用函数时,在函数名后面以空白分隔,给定参数列表即可;例如 FUNCTION_NAME arg1 arg2 …
在函数体中当中,可使用$1, $2, …调用这些参数;还可以使用$@, $*, $#等特殊变量
8、函数中的变量
变量作用域:
环境变量:当前shell和子shell有效
本地变量:只在当前shell进程有效,为执行脚本会启动专用子shell进程;因此,本地变量的作用范围是当前shell脚本程序文件,包括脚本中的函数。
局部变量:函数的生命周期;函数结束时变量被自动销毁
定义局部变量的方法:在函数体中,使用local VAR=VALUE
这样定义之后,该变量的作用范围就仅仅在函数体内部生效,函数结束,则变量不会影响后续脚本中变量的运行
注意:如果函数中有局部变量,如果其名称同本地变量, 使用局部变量
9、函数的递归
函数的递归:函数直接或间接调用自身
例如:数学中的阶乘
N!=N*(N-1)!=N*(N-1)*(N-2)!=…
这样就可以用函数的递归进行计算
jc() {
if [ $1 -eq 0 -o $1 -eq 1 ];then
echo 1
else
echo "$[$1*`jc $[$1-1]`]"
fi
}
例如:斐波那契数列
1,1,2,3,5,8,13,21…
第一个值为1,第二个值为1,随后的每一个值都为其前两个数字之和
求斐波那契数列的第N个数字是多少:(N-1)+(N-2)
fblq() {
if [ $1 -eq 1 -o $1 -eq 2 -o $1 ];then
echo 1
else
echo "$[`fblq $[$1-1]`+`fblq $[$1-2]`]"
fi
}
第三章 函数效果举例
1、编写服务脚本/root/bin/testsrv.sh,完成如下要求
(1) 脚本可接受参数:start, stop, restart, status
(2) 如果参数非此四者之一,提示使用格式后报错退出
(3) 如是start:则创建/var/lock/subsys/SCRIPT_NAME, 并显示“启动成功”
考虑:如果事先已经启动过一次,该如何处理?
(4) 如是stop:则删除/var/lock/subsys/SCRIPT_NAME, 并显示“停止完成”
考虑:如果事先已然停止过了,该如何处理?
(5) 如是restart,则先stop, 再start
考虑:如果本来没有start,如何处理?
(6) 如是status, 则如果/var/lock/subsys/SCRIPT_NAME文件存在,则显示“SCRIPT_NAMEis running…”如果/var/lock/subsys/SCRIPT_NAME文件不存在,则显示“SCRIPT_NAME is stopped…”其中:SCRIPT_NAME为当前脚本名
(7)在所有模式下禁止启动该服务,可用chkconfig 和 service命令管理
#!/bin/bash # Autor: nwc # Version: 2.0 # CreateTime: 2016-08-19 # Description: # 关于第7条的实现,考虑可以将脚本放到/etc/init.d目录下,在脚本开头注释段标明“# chkconfig:运行级别 启动优先级 关闭优先级” # 然后运行chkconfig --add 脚本名 --level 指定哪些级别开机启动 FILE=/tmp/$0 START() { if [ -f $FILE ];then echo "$0 has been start" else touch $FILE && echo "Start success" || echo "Start fail" fi } STOP() { if [ -f $FILE ];then rm -rf $FILE && echo "Stop success" || echo "Stop fail" else echo "$0 has been stopped" fi } RESTART() { STOP START } STATUS() { [ -f $FILE ] && echo "$0 is running..." || echo "$0 is stopped..." } read -p "Please input you choice start|stop|restart|status: " CH case $CH in start) START ;; stop) STOP ;; restart) RESTART ;; status) STATUS ;; *) echo "bad choice..." ;; esac
执行效果如下:
2、编写脚本/root/bin/copycmd.sh
(1) 提示用户输入一个可执行命令名称;
(2) 获取此命令所依赖到的所有库文件列表
(3) 复制命令至某目标目录(例如/mnt/sysroot)下的对应路径下;
如:/bin/bash ==> /mnt/sysroot/bin/bash
/usr/bin/passwd==> /mnt/sysroot/usr/bin/passwd
(4) 复制此命令依赖到的所有库文件至目标目录下的对应路径下:
如:/lib64/ld-linux-x86-64.so.2 ==> /mnt/sysroot/lib64/ld-linux-x86-64.so.2
(5)每次复制完成一个命令后,不要退出,而是提示用户键入新的要复制的命令,并重复完成上述功能;直到用户输入quit退出
#!/bin/bash # Autor: nwc # Version: 2.0 # CreateTime: 2016-08-19 # Description: CMDCP() { DIR=`dirname $CmdPath` if [ -d ${LuJing}${DIR} ] ;then cp $CmdPath ${LuJing}${DIR} && echo "cp $CMD success" || echo "cp $CMD fail" else mkdir -p ${LuJing}${DIR} cp $CmdPath ${LuJing}${DIR} && echo "cp $CMD success" || echo "cp $CMD fail" fi } CMDLIBCP() { for i in ${LibCmd} ; do LIBDIR=`dirname $i` if [ -d ${LuJing}${LIBDIR} ];then cp $i ${LuJing}${LIBDIR} && echo "cp $i success" || echo "cp $i fail" else mkdir -p ${LuJing}${LIBDIR} cp $i ${LuJing}${LIBDIR} && echo "cp $i success" || echo "cp $i fail" fi done } while true;do read -p "Input a exec program name like ls/cat... q for quit " CMD case $CMD in q) echo "exit..." exit ;; *) if which --skip-alias $CMD &>/dev/null && [[ $CMD != "q" ]]; then CmdPath=`which --skip-alias $CMD` LibCmd=`ldd $CmdPath|grep -o -E "/[^[:space:]]+"` LuJing=/tmp/command CMDCP CMDLIBCP else echo "you input is not a right command" continue fi ;; esac done
执行效果如下:
原创文章,作者:M20-1倪文超,如若转载,请注明出处:http://www.178linux.com/37714
评论列表(1条)
总结的很详细,作业也完成的很用心,关于shell脚本主要是多抽时间写,看,学习别人的思想,只有养成了编程的思想,才能写出优秀的代码。