zoukankan      html  css  js  c++  java
  • Linux Shell脚本编程-函数

    函数介绍
      定义:把一段独立功能的的代码当做一个整体,并为之一个名字,命名的代码段,此即为函数;
      功能:函数function是由若干条shell命令组成的语句块,实现代码重用和模块化编程。
      注意:定义函数的代码段不会自动执行,在调用时执行;所谓函数调用,就在代码中给定函数名称即可;函数名出现的任何位置,在代码执行时,都会被自动替换为函数代码;

      函数和shell程序比较相似,区别在于:
      Shell程序在子Shell中运行,而函数在当前Shell中运行。因此在当前Shell中,函数可以对shell中变量进行修改;
      它与shell程序形式上是相似的,不同的是它不是一个单独的进程,不能独立运行,而是shell程序的一部分。

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

      函数的定义和使用:
      可在交互式环境下定义函数
      可将函数放在脚本文件中作为它的一部分(自己定义自己用)
      可放在只包含函数的单独文件中
      函数调用:函数只有被调用才会执行
      调用方法:在代码中给定函数名称,函数名出现的地方,会被自动替换为函数代码
      函数的生命周期:被调用时创建,返回时终止

    函数的两种返回值
      函数的执行结果返回值:使用echo或printf命令进行输出;函数体中调用命令的输出结果
      函数的退出状态码:其状态返回结果为函数中执行的最后一条命令的状态结果
      自定义退出状态码:return
      return [0-255] :从函数中返回,用最后状态命令决定返回值
        0:成功,无错误返回
        1-255:失败,有错误返回

    示例:给定一个用户名,显示其用户名,id和默认的shell
    #!/bin/bash
    #
    userinfo() {
      if id $username &> /dev/null; then
        getent passwd $username| cut -d: -f1,3,7
      else
        echo "No such user"
    fi
    }

    [ $# -lt 1 ] && echo "At least one username." && exit 2

    username=$1
    userinfo

    username=$2
    userinfo

    示例:以函数的方式改写服务框架脚本
    #!/bin/bash
    #
    #chkconfig: - 50 50
    #description: test service scipt
    #

    prong=$(basename $0)
    lockfile=/var/lock/subsys/$prong

    start() {
      if [ -f $lockfile ];then
        echo "$prong is running yet."
      else
        touch $lockfile
        [ $? -eq 0 ] && echo "start $prong finished."
      fi
    }
    stop() {
      if [ -f $lockfile ];then
        rm -f $lockfile
        [ $? -eq 0 ] && echo "stop $prong finished."
      else
        echo "$prong is not running."
      fi
    }
    status() {
      if [ -f $lockfile ];then
        echo "$prong is running"
      else
        echo "$prong is stopped"
      fi
    }

    usage() {
      echo "Usage: $prong {start|stop|restart|status}"
    }

    case $1 in
    start)
      start
      ;;
    stop)
      stop
      ;;
    restart)
      stop
      start
      ;;
    status)
      status
      ;;
    *)
      usage
      exit 1
    esac

    函数定义及用法详述
      函数可以定义在三个场景:交互环境下、脚本中 、单独的函数文件
      1、交互环境下定义和使用函数:
      示例:键入函数名,注意左大括号和函数体之间需要有空格。这里要注意优先级,如果函数名和定义的别名、内部命令外部命令同名,优先级为:别名>函数>内部命令>外部命令;以该方法定义的函数将一直保留到用户从系统退出,或执行了unset命令:
    [root@centos7 function]# fun() { who; hostname ;}
    [root@centos7 function]# fun
    root pts/0 2017-03-02 09:39 (192.168.1.101)
    centos7

      2、在脚本文件中定义和使用函数
      方法:函数在使用前必须定义,因此应将函数定义放在脚本开始部分,直至shell首次发现它后才能使用;调用函数仅使用其函数名即可。
      注意:在脚本中的函数在外面是用不了的,因为不在同一个shell中,运行脚本是开了一个子shell,而在外面是父shell。
    示例:
    #!/bin/bash
    #

    fun1() {
      echo "this is fun1"
    }

    echo "fun1 before"
    fun1
    echo "fun1 after"

    # 执行结果如下:
    [root@centos7 function]# bash test1.sh
    fun1 before
    this is fun1 # 函数只有在被调用才会执行
    fun1 after


      3、使用函数文件定义函数
      可以将经常使用的函数存入函数文件,然后将函数文件载入shell。文件名可任意选取,但最好与相关任务有某种联系。例如:functions.main
      一旦函数文件载入(source或.)shell,就可以在命令行或脚本中调用函数。可以使用set命令查看所有定义的函数,其输出列表包括已经载入shell的所有函数。若要改动函数,首先用unset命令从shell中删除函数。改动完毕后,再重新载入此文件

      函数文件载入shell的格式:
        . /PATH/TO/SOMEFILE或者source /PATH/TO/SOMEFILE

      查看是否载入:
        用source或 . 载入shell后,可使用set命令检查函数是否已载入。set命令将在shell中显示所有的载入函数
        
      删除shell函数:
        现在对函数做一些改动。首先删除函数,使其对shell不可用。使用unset命令完成此功能。
        命令格式为:unset function_name

      在脚本中载入函数:在脚本中使用函数,只要source FILES或者. FILE(存放函数的文件),就可以载入到当前shell当中,调用函数了。
     注意:
      1、Shell函数在当前Shell中运行。因此在当前Shell中,函数可以对shell中变量进行修改;
      2、当函数载入到当前环境中或脚本中时,当前环境或者脚本中定义的变量会和函数中定义的变量起冲突,这是因为,我们在当前环境中或者脚本中定义的为本地变量,函数载入当前shell之后,其实就是当前shell的一部分,所以定义的本地变量对其也有效。为了避免这种冲突,函数要使用局部变量。

    示例:
    1、首先创建一个函数文件,此函数文件中可以存放多个函数;
    [root@centos7 function]# cat funs
    #!/bin/bash
    #

    fun1() {
      echo "This is fun1"
    }

    fun2() {
      echo "This is fun2"
    }
    2、在当前shell中要想调用此函数,要使用 source 或者 . 加载到当前shell 中方可
    # 直接调用,bash(相当于开了一个子shell)都不行
    [root@centos7 ~]# fun1
    -bash: fun1: 未找到命令

    [root@centos7 ~]# bash fun1 # 相当于
    bash: fun1: 没有那个文件或目录

    # source 加载到当前shell
    [root@centos7 ~]# source /root/bin/function/funs
    [root@centos7 ~]# fun1
    This is fun1
    [root@centos7 ~]# fun2
    This is fun2

    # 删除shell函数,再执行就没有了
    [root@centos7 ~]# unset fun1
    [root@centos7 ~]# fun1
    -bash: fun1: 未找到命令
    [root@centos7 ~]# fun2
    This is fun2
    [root@centos7 ~]# unset fun2
    [root@centos7 ~]# fun2
    -bash: fun2: 未找到命令
    3、在脚本中使用函数,只要source FILES或者. FILE(存放函数的文件),就可以载入到当前shell当中,调用函数了。
    [root@centos7 function]# cat test2.sh
    #!/bin/bash
    #
    source /root/bin/function/funs
    fun1
    echo "taotao"
    fun2

    # 执行结果如下:
    [root@centos7 function]# fun1
    -bash: fun1: 未找到命令 # 在当前shell中不能使用,因为脚本为子shell,当前环境为父shell
    [root@centos7 function]# fun2
    -bash: fun2: 未找到命令

    [root@centos7 function]# bash test2.sh
    This is fun1
    taotao # 调用函数成功
    This is fun2

    函数参数:
      函数可以接受参数:
        传递参数给函数:调用函数时,在函数名后面以空白分隔给定参数列表即可;例如"testfunc arg1 arg2 ..."
        在函数体中当中,可使用$1, $2, ...调用这些参数;还可以使用$@, $*, $#等特殊变量

    示例1:
    1、添加10个用户,(添加用户的功能使用函数实现),用户名作为参数传递给函数
    [root@centos7 function]# cat useradd.sh
    #!/bin/bash
    #
    addusers () {
      if id $1 &> /dev/null; then
        return 5
      else
        useradd $1
        retval=$? # 表示函数的状态返回值,这里如果添加成功则为0
        return $retval #
      fi
    }

    for i in {1..10};do
      addusers ${1}${i} # $1 为脚本传递的参数变量,$i 为循环体中i的变量
      renum=$? # 这里的状态返回值取决于函数中 return 的值,为0,表示添加成功,为5表示用户存在
      if [[ "$renum" -eq 5 ]];then
        echo "user ${1}${i} exits."
      elif [[ "$renum" -eq 0 ]];then
        echo "Add user ${1}${i} successd."
      else
        echo "Unknow Error."
      fi
    done

    函数变量:
      变量的作用域:
      环境变量:当前shell和子shell有效
      本地变量:只在当前shell进程有效,为执行脚本会启动专用子shell进程;因此本地变量的作用范围是当前shell脚本程序文件,包括脚本中的函数
      局部变量:作用域是函数的生命周期;函数结束时变量被自动销毁

      在函数中定义局部变量的方法:
      local NAME=VALUE

      注意:
      函数中也可调用本地变量,如果函数中定义的变量名称和本地变量相同,函数调用之后会覆盖本地变量的值;为了避免和本地变量相冲突,使之互不干扰,所以在函数中使用的变量要使用局部变量

    示例:
    1、在函数中定义的本地变量和脚本中定义的本地变量名相同,但值不同的执行结果;
    [root@centos7 function]# cat test.sh
    #!/bin/bash
    #

    setname() {
      name=jerry
      echo "Function:$name"
    }

    name=tom
    echo "Fun before:$name"
    setname
    echo "Fun after:$name"

    #执行结果,可以发现 函数中定义的变量覆盖了脚本中定义的变量,
    [root@centos7 function]# bash test.sh
    Fun before:tom # 脚本执行前为本地变量
    Function:jerry # 调用函数,函数也会调用本地变量,并再次给其赋值
    Fun after:jerry # 脚本中定义的变量被函数中定义的变量覆盖

    2、在函数中定义局部变量,和脚本中定义本地变量但值不同的结果:
    [root@centos7 function]# cat test.sh
    #!/bin/bash
    #

    setname() {
      local name=jerry
      echo "Function:$name"
    }

    name=tom
    echo "Fun before:$name"
    setname
    echo "Fun after:$name"

    #执行结果如下:
    [root@centos7 function]# bash test.sh
    Fun before:tom
    Function:jerry
    Fun after:tom
    结论:
      如果函数中有局部变量,如果其名称同本地变量,使用局部变量。否则,函数执行之后会把当前shell中定义的相同的变量覆盖。
      定义的局部变量只是在函数内部使用,互不干扰;如果不加local就是本地变量了。
    函数递归:

    函数递归:
      函数直接或间接调用自身
      递归实例(阶乘):
      阶乘是所有小于及等于该数的正整数的积,0的阶乘为1,自然数n的阶乘写作n!。
      阶乘亦可以递归方式定义:
        n! = n(n-1)! = n(n-1)(n-2)! = n(n-1)(n-2)(n-3)...1
        0! = 1
        
    示例1:给定一个正整数,求其阶乘:
    [root@centos7 function]# cat jiecheng.sh
    #!/bin/bash
    #

    fab() {
      if [ $1 -eq 0 -o $1 -eq 1 ];then
        echo 1
      else
        echo $[$1*$(fab $[$1-1])]
      fi
    }

    fab $1

    #执行结果如下:
    [root@centos7 function]# bash jiecheng.sh 2
    2
    [root@centos7 function]# bash jiecheng.sh 5
    120
    [root@centos7 function]# bash jiecheng.sh 3
    6

  • 相关阅读:
    linux uart驱动——相关数据结构以及API(二)
    linux uart驱动——uart原理(一)
    linux SPI驱动——spidev之driver(六)
    linux SPI驱动——spidev之deive(五)
    linux SPI驱动——spi core(四)
    linux SPI驱动——gpio模拟spi驱动(三)
    linux SPI驱动——spi协议(一)
    在dev目录创建一个字符设备驱动的流程
    web audio living
    use html5 video tag with MSE for h264 live streaming
  • 原文地址:https://www.cnblogs.com/Link-Luck/p/9855100.html
Copyright © 2011-2022 走看看