分享

Shell中的函数调用

 liang1234_ 2017-12-27

本章学习内容

        ----------函数介绍

        ----------函数定义

        ----------函数使用

        ----------区分returnexit

        ----------删除函数

        ----------注意事项



    

1、介绍函数 

    通俗地讲,函数就是将一组功能相对独立的代码集中起来,形成一个代码块,这个代码可以完成某个具体的功能(这里理解为命令的堆积也可以)。从本质上讲,函数是一个函数名到某个代码块的映射。也就是说,用户在定义了函数之后,就可以通过函数名来调用其所对应的一组代码(称为函数调用)。




2、定义函数

    <1>俩种方式     

       ▲function fname {

           command
           command
         }

       ▲fname {

           command
           command
         } 

    <2>函数名不能和命令相同,命令优先级高于函数

    <3>函数命名规则

       不可与命令相同,否则命令无法正常使用。  

       函数优先级>命令

       不可定义与函数名同名的别名,否则函数无法使用。

       别名优先级>函数

       所以优先级:别名 >  函数   >  命令

    <4>函数中的变量设为局部变量,防止与shell的变量冲突

       验证

# 创建函数文件fun2,定义test函数 [root@localhost ~]#vim fun2 function test() {  a=first  echo 'a=$a' } # 编写脚本testfun2.sh [root@localhost ~]#vim testfun2.sh  #!/bin/bash # a=second source fun2 test echo 'a=$a' # 执行脚本 [root@localhost ~]#bash testfun2.sh  a=first a=first

结果表明虽然脚本中定义了a=second,但是执行test函数之后,已经变成了first。为了解决脚本中变量和函数中变量的混淆,一般将函数中的变量定义为局部变量。




3、使用函数

    <1>载入函数

       子shell中如果需要使用父shell中的函数,需要将函数加载至本shell

       加载方式

           source FUNCTION

           . FUNCTION      

       注:修改函数之后,必须重新载入shell才能生效

    <2>调用函数

       输入函数名再加参数即可 




4、函数返回值return和exit的不同

    return:退出当前函数

        return :从函数中返回,用最后状态命令决定返回值

        return 0 :无错误返回。

        return 1-255 :有错误返回

    exit:退出当前脚本




5、删除函数

    unset FUNCTION:删除函数

    set:查看所有定义的函数




6、关于函数参数传递问题

    不知道大家有没有过这样的疑问,在函数中参数是如何传递的呢?因为在C语言中是这样定义一个函数的:int cmp(int a, int b),变量已经在函数中声明。但是shell中的函数并没有定义参数,这个过程是怎么完成的呢?小编刚开始也很疑惑,后来才明白shell的函数中通过函数位置变量和变量的引用就可以实现参数的传递。下面是一些示例以及传参的注意事项,大家可以参考一下。

# 创建函数文件fun1,定义函数add function add() { local sum  sum=$[$1 $2]  echo $sum } # 编写脚本testfun1.sh #!/bin/bash source fun1 add $1 $2 ####执行脚本: [root@localhost ~/bin]#bash funadd.sh 1 2 3

脚本中的$1和$2是脚本引用命令行的位置变量,而函数中的$1和$2是引用脚本中的第一个变量和第二个变量,我们称其为函数位置变量。(实现传参的方法之一)

看下面这种情况

# 创建函数文件fun1,定义函数add function add() { local sum  sum=$[$1 $2]  echo $sum } # 编写脚本testfun1.sh #!/bin/bash source fun1 read -p 'Please input two figures:' a b    # 只添加此行 add $1 $2 # 执行脚本 [root@localhost ~/bin]#bash funadd.sh  Please input two figures:1 2 /root/bin/fun1: line 3:  : syntax error: operand expected (error token is ' ')

为什么这里会报错呢?因为在脚本中引用的位置变量$1和$2并不是1和2,也就是说$1和$2并没有值,函数中并没有引用到数值,计算结果当然是错的。从侧面也说明了read是无法引用位置变量的。

那么,该怎么解决呢?答案如下

#!/bin/bash source fun1 read -p 'Please input two figures:' a b add $a $b                          # 只改变此行 [root@localhost ~/bin]#bash funadd.sh  Please input two figures:1 2 3

因为此时的$a和$b引用了命令行输入的1和2,而函数中又会调用这俩个值,结果计算正确。

再看一种情况

# 创建函数文件fun1,定义函数add function add() {   local sum   sum=$[$a $b]   echo $sum } # 编写脚本testfun1.sh #!/bin/bash source fun1 read -p 'Please input two figures:' a b add $1 $2   或者   add  $a $b   或者   add a b   # 三种情况 # 执行脚本 [root@localhost ~/bin]#bash funadd.sh  Please input two figures:1 2 3

小编已经实验过,这三种情况都能运行出结果,为了书写简便,都一一列举再在此处。但是大家知道这是为什么吗?因为函数直接引用了命令行的参数(实现传参的方法之二,弱类型编程语言特有的变量引用),也就不需要通过脚本来传参了。所以交互式输入的脚本中调用的函数如果没有使用$1和$2之类的字符来引用变量,而是直接使用了$a和$b之类的字符,那是此时传参的意义也就不存在了。

不过在非交互式的脚本中调用的函数也可以直接调用脚本中的变量(实现传参的方法之三)


再举一个例子加深一下印象

# 创建函数文件fun3,定义函数string function string() { if [ $1 == ha ]; then   echo 'nihao' fi } # 编写脚本testfun3.sh #!/bin/bash # source fun3 a=ha string $a unset a ####执行脚本 [root@localhost ~]#bash testfun3.sh  nihao

# 创建函数文件fun3,定义函数string function string() { if [ $a == ha ]; then   echo 'nihao' fi } # 编写脚本testfun3.sh #!/bin/bash # source fun3 a=ha string $a  或者  string $1  或者  string unset a ####执行脚本 [root@localhost ~]#bash testfun3.sh  nihao




课后强化练习

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

# 创建函数文件testsrv,定义多个函数 [root@localhost ~/bin/dir]#vim testsrv function start() {     if [ -e /var/lock/subsys/testsrv.sh ]; then       echo 'Already start...'     else       touch /var/lock/subsys/testsrv.sh       echo 'start ok'     fi } function stop() {     if [ ! -e /var/lock/subsys/testsrv.sh ]; then       echo 'Already stop...'     else       rm -f /var/lock/subsys/testsrv.sh       echo 'stop ok'     fi } function restart() {     stop      start  } function status() {   if [ -e /var/lock/subsys/testsrv.sh ]; then     echo 'testsrv.sh is running...'   else     echo 'testsrv.sh is stopped...'   fi } function quit() {   exit 2 } function again() {   while [ $1 != start -a $1 != stop -a $1 != restart -a $1 != status ]; do   read -p 'Error,please enter again:' CHOICE   done }       # 最后一个函数未使用,问题。 # 编写脚本testsrv3.sh    source /root/bin/dir/testsrv cat << EOF four choices for you: start) stop) restart) status) EOF read -p 'please input your choice(start|stop|restart|status|quit):' CHOICE   while [ $CHOICE != 'start' -a $CHOICE != 'stop' -a $CHOICE != 'restart' -a $CHOICE != 'status' ]; do     read -p 'Error,please enter again:' CHOICE    done case $CHOICE in  start)   start    ;; stop)    stop   ;; restart)    restart    ;; status)    status   ;; quit)   quit    ;; esac

或者使用select

# 函数不变,改写脚本 #!/bin/bash source testsrv PS3='please input your choice:' select CHOICE in start stop restart status quit; do   case $CHOICE in   start)     start     ;;   stop)     stop      ;;   restart)     restart      ;;   status)     status     ;;   quit)     quit      ;;   *)     echo 'Error,please enter again...'   esac done

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退出

# 创建函数文件copycmd,定义多个函数 function query() {   ldd /usr/bin/$1 } function copy() {   mkdir /mnt/sysroot &> /dev/null   local dir1   dir1=/mnt/sysroot   cp /usr/bin/$1 $dir1   mkdir /mnt/sysroot/lib64 &> /dev/null   local dir2   dir2=/mnt/sysroot/lib64   cp `ldd /usr/bin/ls | sed -r 's@[[:space:]] .*=>?[[:space:]]?(.*)[[:space:]].*@\1@'` $dir2 &> /dev/null } function quit() {   if [ $1 == quit ]; then     exit   fi } # 编写脚本copycmd4 #!/bin/bash source copycmd PS3='Please input your option:' select option in run quit; do   # 列出俩个选项,是否运行或者退出,select自带循环功能   case $option in                      退出即可,option是run和quit   run)     read -p 'Input your cmd:' CMD   # 赋初值,否则无法与quit比较,直接错误                                                            until [[ $CMD == quit ]]; do       if  which $CMD &> /dev/null; then         query $CMD           # 调用函数         copy $CMD            # 调用函数       else         read -p 'Error,again:' CMD         fi     read -p 'Input your cmd:' CMD   # 纠正初值,与quit比较     done   ;;   quit)     quit $option   ;;   esac done




    本站是提供个人知识管理的网络存储空间,所有内容均由用户发布,不代表本站观点。请注意甄别内容中的联系方式、诱导购买等信息,谨防诈骗。如发现有害或侵权内容,请点击一键举报。
    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约

    类似文章 更多