Shell编程之select循环&函数详解

一、select循环

       功能:主要用于创建菜单,菜单按数字顺序排列。并将PS3变量的值用作用户输入提示。用户的选择被保存在内置变量REPLY中。也可以和case语句结合,在select循环中对用户的输入作出判断并处理。

       注意:select循环为无限循环,因此需要给出循环退出条件。

例1:让用户选择其来自哪个省市

#!/bin/bash
#

echo "where are you come from"
PS3="i came from :"
declare -a cm=('beijing' 'shanghai' 'hainan' 'hebei' 'hunan')
select path in ${cm[@]} 
do
	break
done
echo "you are from $path"

blob.png

 例2:询问用户是哪个足球俱乐部的球迷,并显示该俱乐部的教练。当用户输入quit时,退出。

#!/bin/bash
#

echo "Which football club is your favorite(quit to exit):"
PS3="my favorite is : "
select path in 'ManUnited' 'Barcelona' 'Chelsea' 'RealMadrid' 'quit'
do
	case $path in
		ManUnited)
		echo "you are $path fans"
		echo "$path coah is Jose mourinho"
		;;
		Barcelona)
		echo "you are  $path fans"
		echo "$path coah is Enrique"
		;;
		Chelsea)
		echo "you are  $path fans"
		echo "$path coah is Conti"
		;;
		RealMadrid)
		echo "you are  $path fans"
		echo "$path coah is Zidane"
		;;
		quit)
		echo "See you..."
		exit
		;;
		*)
		echo "Unknown option."
		continue
		;;
	esac
done

blob.png

 

二、函数

       介绍:函数是由若干条shell命令组成的语句块,实现代码重用和模块化编程。

       应用场景:在编写shell脚本时,有些代码会被反复重用多次,把这些可能重复使用的代码写成函数,这样就可以通过函数名调用来高效、重复地利用。另外,当shell脚本功能比较复杂时,可以将脚本划分为多个模块,不同模块可以写成不同的函数。

       2.1函数的语法格式:

              格式1、

                     f_name () {

                            函数体…

}

             

              格式2、

                     function f_name  {

                            函数体…

}

       2.2函数的生命周期:被调用时创建,返回时终止。

       2.3函数的调用:

              函数要能被调用,需在调用前进行定义。调用时直接键入函数名即可。例:

blob.png

              若不调用函数,则函数不会被执行。

blob.png 

       2.4函数的返回值: 

       分为两种

              a、正常返回的数值:

                     (1)函数中的打印语句,如echo、print

                     (2)函数中命令的执行结果 

示例1:函数执行成功之后,会将用户输入的指令输出

blob.png

如何获取函数的输出。有时候我们需要对函数正常输出的数值进行处理,这时可以通过下面的方式获取函数的输出

示例2:将函数执行之后的输出保存,进行处理

blob.png

              b、执行状态返回值:

                     (1)取决于函数中执行的最后一条语句的执行状态

                     (2)也可通过return自定义

                            return N(0-255)

              在示例3中,可以观察到,函数的执行状态取决于函数中执行的最后一条语句的执行状态;但是没办法判断函数中的其他语句是否执行成功,当需要根据函数中不同的语句的执行状态做出判断;来决定后续的操作时,需要用到return。如示例4。

#!/bin/bash
#
user_input () {
	read -p "please enter an excuteable command : " cmd
	echo $cmd
	ls /etc/justfortest
}
user_input
echo "Funtion status is $?"

blob.png

在示例4中,需要判断用户输入的用户是否存在,存在时,返回5的状态值;用户不存在时,添加用户,根据添加用户的命令的执行状态来判断添加是否成功。

blob.png 

       2.5在脚本中调用函数:

              在一个脚本中想要调用写在另一个脚本中的函数,同过source  ”脚本名“来实现

 cacufun.sh脚本内容如下:cacufun.sh定义了加减乘除4中运算的函数

#!/bin/bash
#
addtion_num() {
	local res=`echo "$1 $2 $3"| bc`
	echo "result is $res"
}

subtract_num() {
	local res=`echo "$1 $2 $3"| bc`	
	echo "result is $res"
}

multiplication_num() {
	local res=`echo "$1 $2 $3"| bc`	
	echo "result is $res"
}

devision_num() {
	local res=`echo "$1 $2 $3"| bc`	
	echo "result is $res"
}

在cacutest.sh脚本中调用cacufun.sh脚本中的函数,实现对用户输入数据的运算。

#!/bin/bash
#
source /root/bin/practice/cacufun.sh

read -p "enter two int number to caculate: " num1 num2 num3
case $num2 in
	+)
	echo "$num1 $2 $num3 " `addtion_num $num1 $num2 $num3`
	;;
	-)
	echo "$num1 $2 $num3 " `substract_num $num1 $num2  $num3`
	;;
	*)
	echo "$num1 $2 $num3 " `multiplication_num $num1 $num2 $num3`
	;;
	/)
	cho "$num1 $2 $num3 " `devision_num $num1 $num2 $num3`
	;;
	*)
	echo "wrong option"
	exit 123
esac

blob.png 

       2.6函数参数:

              函数可以使用类似于调用脚本位置参数来调用函数的参数

              函数的参数表示:

                     $1,$2

                     $#

                     $@,$*

       函数中的$1,$2…指的是传递给函数的参数,而不是传递个脚本的参数

 blob.png

       2.7 shell脚本中的变量作用域:

              1、在函数中使用了在主程序中声明的变量,重新赋值会直接修改主程序中的变量。

              2、如果想让函数中的变量与主程序中的变量冲突,在函数中声明变量时,使用local修饰,将变量声明为局部变量,其作用域仅限于当前函数。

              3、变量被声明的位置决定了其作用域,

                     3.1 在函数中使用了在主程序中没有声明的变量,在函数执行结束后即被撤销,无论是否使用local修饰符

                     3.2 在函数中声明了主程序中声明过的变量,这两个变量为不同的变量。函数中的变量在执行结束后即被撤销。

       2.8 shell脚本中变量的查找顺序:

              1、内层函数本身

              2、外层还是定义的

              3、主程序

              4、shell环境变量

      

2.9 函数的递归:

       函数直接或调用自身

       示例:

       斐波那契数列又称黄金分割数列,因数学家列昂纳多· 斐波那契以兔子繁殖为例子而引入,故又称为“兔子数列”,指的是这样一个数列:0 、1、1 、2 、3 、5 、8 、13 、21 、34 、…… ,斐波纳契数列以如下被以递归的方法定义:F (0 )=0 ,F (1 )=1 ,F (n )=F(n-1)+F(n-2) (n≥2) )

写一个函数,求n阶斐波那契数列

#!/bin/bash
#

fab () {
	if [[ $1 -eq 1 || $1 -eq 2 ]];then
		echo -n "1 "
	else
		echo -n "$[$(fab $[$1-1])+$(fab $[$1-2])] "
	fi
}

for i in $(seq 1 $1)
do
	fab $i
done
echo

blob.png


三、实战演练

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为当前脚本名

#!/bin/bash
#
srv_file=/var/lock/subsys/$0
srv_name=`basename $0`

usage_srv() {

	if [[ $1 -lt 1  || $1 -ge 2 ]];then
		echo "Wrong option:"
		echo "Usage : $srv_name start|stop|restart|status"
		exit 123
	fi

}


start_srv() {

	if [ -f $srv_file ];then
		echo "service $srv_name already started"
	else
		touch $srv_file && echo "start $srv_name finished"
	fi
		
}
	
stop_srv() {

	if [ ! -f $srv_file ];then
		echo "service $srv_name already stopped"
	else
		rm -f $srv_file &>/dev/null && echo "stop $srv_name finished"
	fi

}

status_srv() {

	if [ -f $srv_file ];then
		echo "service $srv_name is running"
	else
		echo "service $srv_name was stopped"
	fi

}


case $1 in
	start)
		start_srv $1
		;;
	stop)
		stop_srv $1
		;;
	restart)
		stop_srv $1
		start_srv $1
		;;
	status)
		status_srv $1
		;;
	*)
		usage_srv $#
	;;
esac

blob.png

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
#

f_dir=/mnt/sysroot

cmd_input () {
	while true
	do
		read -p "Please input an excuteable command to backup (quit to exit): " cmd
		if [[ -z $cmd ]];then
			echo "wrong option,try again..."
			continue
		elif [[ $cmd == "quit" ]];then
			exit 88
		elif ! which --skip-alias $cmd &>/dev/null;then
			echo "No such command,try again..."
			continue
		else
			break
		fi
	done

}

cp_cmd() {

	cmd_path=`which  --skip-alias $cmd`
	cmd_dir=`dirname $cmd_path`
	[ ! -d $f_dir$cmd_dir ] && mkdir -p $f_dir$cmd_dir 
	cp $cmd_path $f_dir$cmd_dir && echo "backup $cmd finished"

}

cp_cmd_lib() {

	cmd_lib=`ldd $cmd_path`
	for path in $cmd_lib
	do
		cmd_lib_dir=`echo $path | grep -o -E '/[^[:space:]]+.*/'`
		if [[ ! -d $f_dir$cmd_lib_dir ]];then
			mkdir -p $f_dir$cmd_lib_dir && cp $path $f_dir$cmd_lib_dir &> /dev/null
		else
			cp $path $f_dir$cmd_lib_dir &> /dev/null
		fi
	done
	echo "backup ${cmd}'s library finished"

}

main() {

	while true
	do
		cmd_input  
		cp_cmd
		cp_cmd_lib
	done

}

main

原创文章,作者:M20-1钟明波,如若转载,请注明出处:http://www.178linux.com/38011

(0)
M20-1钟明波M20-1钟明波
上一篇 2016-08-21 20:46
下一篇 2016-08-21 20:46

相关推荐

  • LVS的工作原理

    LB Load Balancing:解决方案 硬件: F5 BIG-IP 思杰 Citrix Netscaler A10 A10 Array  Redware 软件:lvs  linux Virtual Server 作者章文嵩博士 ipvs相当于netfilter,工作在内核中,将用户转发    框架,需要依赖以规则…

    Linux干货 2016-12-07
  • 细节决定成败–空格的巨大作用以及正则表达式中元字符的转义

    字符串的条件判定 1.字符串判定 一定要用双[[ ]] 2.字符串判定=~默认支持扩展正则表达式,这里注意双引号的使用 仅仅做是否包含时,有无双引号无区别。 但是利用其他扩展表达式时 双引号一定要去掉 锚定示例 多条件判定时-o -a使用时,不能使用双中括号 空格有无的差别 !的使用细节 !到目前为止 有两种意义 条件判定取反 历史命令的调用 两者的使用却别…

    2017-03-19
  • 第一周博客 计算机组成及Linux基础入门

    1、描述计算机组成及其功能。
    2、描述罗列Linux的发行版,并描述不同发行版之间的联系和区别。
    3、描述Linux的哲学思想,并按照自己的理解对其进行解释。
    4、说明Linux系统上命令的使用格式,详细介绍ifconfig、echo、tty、startx、export、pwd、history、
    shutdown、poweroff、reboot、hwclock、date命令的使用,并配合相应的示例说明阐述。
    5、如何在Linux系统上获取命令的帮助信息,请详细列出,并描述man文档的章节是如何划分。
    6、请罗列Linux发行版的基础目录名称命名法则及功能规定。

    2017-12-02
  • N22-第七周作业

    1、创建一个10G分区,并格式为ext4文件系统;    (1) 要求其block大小为2048, 预留空间百分比为2, 卷标为MYDATA, 默认挂载属性包含acl;    (2) 挂载至/data/mydata目录,要求挂载时禁止程序自动运行,且不更新文件的访问时间戳; [root@localhost ~]# fd…

    Linux干货 2016-10-07
  • Linux学习之数据重定向

    大纲: 一、数据重定向定义 二、数据重定向分类 三、数据重定向作用 四、示例 一、数据重定向:命令的运行的结果默认输出在监视器上,重定向就是把这个结果输出到其它地方或其它文件。 二、数据重定向分类: 1.标准输出: (standard output,简称stdout,代码为 1 ,使用 > 或 >>):命令执行成功输出的正确提示信…

    Linux干货 2015-06-24
  • 破坏grub实验之二

    删除/etc/fstab和/boot和grub的stage1阶段 [root@localhost ~]# rm -rf /boot [root@localhost ~]# rm -rf /etc/fstab  [root@localhost ~]# …

    Linux干货 2016-09-28

评论列表(2条)

  • 马哥教育
    马哥教育 2016-08-22 13:50

    总结的很好,态度很端正,加油。

    • M20-1钟明波
      M20-1钟明波 2016-08-23 22:56

      @马哥教育好的,谢谢