Select    循环与菜单 


    它的主要用于创建菜单,按数字排列顺序的菜单项将呈现出列表的形式显示在标准错误输出上,并显示PS3提示符请求用户输入(默认时,PS3的值为"#?")。心啊是PS3提示符后,shell等待用户输入,输入的应当是菜单列表中的一个数字,输入值会保存在一个shell的特殊变量REPLY中国,它与选项列表中相应的括号后面的字符串相关联。

    case命令和select命令联合使用时,用户可以从菜单中进行选择,并基于选项执行相应的命令。


1)select 格式

    select variable in list
    do
    循环体命令
    done

2)select与case联合使用

[root@localhost newbin]# vi select.sh 

  1 #!/bin/bash
  2 #function: select
  3 #author: xiaoshui
  4 PS3="please input a subject: "
  5 select var in language math english  quit;do //
  6     case $var in        //通过case命令将用户选择执行对应的命令。
  7     language)  
  8         echo "you want to study $var"
  9         echo $REPLY    //通过REPLY变量保存显示出用户的输入
 10         ;;
 11     math)
 12         echo "you want to study $var"
 13         echo $REPLY
 14         ;;
 15     english)
 16         echo "you want to study $var"
 17         echo $REPLY
 18         ;;
 19     quit)
 20         echo $REPLY
 21         exit
 22         ;;
 23     *)                //如果用户输入的不在列表之中,返回下面内容
 24         echo "must be language|math|english|quit"
 25         echo $REPLY
 26         ;;
 27     esac
 28 done
[root@localhost newbin]# bash select.sh 
1) language
2) math
3) english
4) quit
please input a subject: 1    //输入1,此时将language赋值给var变量
you want to study language    
1                            //通过REPLY显示出用户输入的是什么
please input a subject: 2
you want to study math
2
please input a subject: 3
you want to study english
3
please input a subject: d
must be language|math|english|quit
d
please input a subject: 4
4
[root@localhost newbin]#

函数:

    把一段独立功能的代码当作一个整体,并为止命名一个名字;命名的代码段,此即为函数;


1)函数的重要规则

    (1)函数必须先定义,后使用

    (2)函数共享调用它的那个脚本的变量

    (3)函数可以接受参数:

        传递参数给函数:

        在函数体当中,可以使用$1,$2..引用传递给函数的参数;还可以在函数中使用$*或$@引用所有参  数,$#引用传递的参数的个数;

        在调用函数时,在函数名后面以空白符分割给定的参数列表即可,例如,testfunc arg1 arg2

    (4)函数返回值:

        函数的执行结果返回值:

            (1)使用echo或printf命令进行输出;

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

        函数的退出状态码:

            (1)默认取决于函数体中执行的最后一条命令的退出状态码;

            (2)自定义:return

    (5)如果在函数中是用exit命令,就会推出整个脚本,即使函数后面还有命令。

    (6)函数可以保存在其他文件中,使用srouce 或 . 将文件载入脚本

    (7)函数递归,即自己调用自己


2)函数的声明

        函数由两部分组成:函数名和函数体。
            语法一:
            function f_name{
            ...函数体...
            }
           语法二:
            f_name() {    
            ...函数体...    
            }

    函数只能在以下几种环境下定义  

        1、可在交互式环境下定义函数
        2、可将函数放在脚本文件中作为它的一部分
        3、可放在只包含函数的单独文件中

[root@localhost newbin]# cat func.sh 
#!/bin/bash
#function: test functions
#author: xiaoshui
fun(){            //fun即为函数名
echo "hello world"    //{}内为函数内容
}

3)函数的使用

    调用:函数只有被调用才会执行;
        调用:给定函数名
    函数名出现的地方,会被自动替换为函数代码

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

[root@localhost newbin]# bash func.sh 
hello world
[root@localhost newbin]# cat func.sh 
#!/bin/bash
#function: test functions
#author: xiaoshui
fun(){                //定义函数,{}里面为函数内容
echo "hello world"
}
fun            //调用函数(只需写上函数名即可)
[root@localhost newbin]#

    


4)函数的返回值

    函数有两种返回值:    
    函数的执行结果返回值:
        (1) 使用echo或printf命令进行输出
        (2) 函数体中调用命令的输出结果
    函数的退出状态码:
        (1) 默认取决于函数中执行的最后一条命令的退出状态码
        (2) 自定义退出状态码,其格式为:
        return 从函数中返回,用最后状态命令决定返回值
        return 0 无错误返回。
        return 1-255 有错误返回

[root@localhost newbin]# cat funcadduser    //定义函数的文件
add(){
if id $1 &> /dev/null;then        //如果id到$1 则返回2
    return 2
else
    useradd $1 &> /dev/null        //反之则返回else语句最后一条命令的命令返回值,即0
fi
}
[root@localhost newbin]# cat funcadduser.sh
#!/bin/bash
#function: diaoyong func
#author: xiaoshui
. funcadduser                //载入函数文件
read -p "input a username you want to add: " Name    //读取变量
[ -z $Name ] && echo "no argue"&&exit
add $Name                    //调用函数
if [ $? -eq 0 ];then        //如果函数返回值为0,则执行then后的语句
    echo "user $Name add success!"
else                        //反之执行else语句
    echo "user $Name exits.."
fi
    
[root@localhost newbin]# 
[root@localhost newbin]# vi funcadduser.sh 
[root@localhost newbin]# bash  funcadduser.sh 
input a username you want to add: xiaoshui    //read 读入变量
user xiaoshui exits..                        //因为xiaoshui用户事先存在
[root@localhost newbin]# bash  funcadduser.sh 
input a username you want to add: nihaoma    
user nihaoma exits..
[root@localhost newbin]# bash  funcadduser.sh 
input a username you want to add: nihaoa    //因为事先没有nihaoa,则success
user nihaoa add success!

    在测试文件时候,发现一个return的小细节。代码如下

[root@localhost newbin]# vi funcadduser

  1 add(){                            //定义的函数和上方一样
  2 if id $1 &> /dev/null;then
  3     return 2
  4 else
  5     useradd $1 &> /dev/null
  6 fi
  7 }
~     
[root@localhost newbin]# vi funcadduser.sh

  1 #!/bin/bash
  2 #function: diaoyong func
  3 #author: xiaoshui
  4 . funcadduser
  5 read -p "input a username you want to add: " Name
  6 [ -z $Name ] && echo "no argue"&&exit
  7 add $Name
  8 if [ $? -eq 0 ];then                //函数返回值如果为0,即useradd success
  9     echo "user $Name add success!"
 10 elif [ $? -eq 2 ];then            //函数返回值如果为2,即exits
 11     echo "user $Name exits.."
 12 else                            //写else之前,本来以为匹配不到这个,所以随便写了一个echo
 13     echo 
 14 fi
[root@localhost newbin]# id xiaoshui            //xiaoshui用户事先存在
uid=1001(xiaoshui) gid=1001(xiaoshui) groups=1001(xiaoshui)
[root@localhost newbin]# bash  funcadduser.sh
input a username you want to add: xiaoshui    //输入xiaoshui,但是却没有出现想象中的exits

[root@localhost newbin]#

        bash -x 查看执行过程

[root@localhost newbin]# bash  -x funcadduser.sh
+ . funcadduser
+ read -p 'input a username you want to add: ' Name
input a username you want to add: xiaoshui
+ '[' -z xiaoshui ']'
+ add xiaoshui
+ id xiaoshui
+ return 2                //return2 没有错,说明add函数没有错
+ '[' 2 -eq 0 ']'        //判断2是否等于0
+ '[' 1 -eq 2 ']'        //结果显示了1是否等于2,忽然间明白了,问题出在这里
+ echo

[root@localhost newbin]#

    通过上述的发现,可以总结为,当if条件执行时,如果没有匹配到条件,会重新刷新返回值,这样后面通过命令返回值比较的结果都没有了意义。谨记

5)函数递归

    函数直接或间接调用自身
    注意递归层数

递归实例

[root@localhost bin]# vi func.sh 

  1 #!/bin/bash
  2 #
  3 fact() {
  4 if [ $1 -eq 0 -o $1 -eq 1 ]; then
  5 echo 1
  6 else
  7 echo $[$1*$(fact $[$1-1])]
  8 fi
  9 }
 10 fact 5
[root@localhost bin]# bash func.sh 
120

                                                                                                                    谢谢浏览