• 十二、函数


    函数的定义

    将shell脚本代码放进代码块封装便于其他地方调用,这样的代码块就叫函数。

    创建函数

    第一种方式

    使用关键字function,后跟函数名,在脚本中函数名必须唯一,如果重复,那么后续的函数会重写前面的函数

    function name {
        commands
    }

    第二种方式

    name() {
    commands
    }

    使用函数

    在脚本行中指定函数名即可

    [root@tzPC 17Unit]# cat test1.sh 
    #!/bin/bash
    #using a function in a script
    function func1 {
        echo "This is an example of a function"
    }
    
    count=1
    while [ $count -le 5 ]
    do
        func1
        count=$[ $count + 1 ]
    done

    返回值

    函数的退出状态码是函数中最后一条命令返回的退出状态码,可以使用$?来查看。

    $?为0便是命令正常执行,其他值表示命令执行有误。

    [root@tzPC 17Unit]# cat test4.sh 
    #!/bin/bash
    #testing the exit status of a function
    func1() {
        echo "trying to display a non-existent file"
        ls -l badfile
    }
    
    echo "testing the function:"
    func1
    echo "The exit status is:$?"
    [root@tzPC 17Unit]# bash test4.sh
    testing the function:
    trying to display a non-existent file
    ls: cannot access badfile: No such file or directory
    The exit status is:2

    return命令返回特定退出状态码

    return命令可以返回一个特定的整数值来定义函数的退出状态码。

    [root@tzPC 17Unit]# cat test5.sh 
    #!/bin/bash
    #using the return command in a function
    function db1 {
        read -p "Enter a value: " value
        echo "doubling the value"
        return $[ $value * 2 ]
    }
    
    db1
    echo "The new value is $?"
    [root@tzPC 17Unit]# bash test5.sh
    Enter a value: 50
    doubling the value
    The new value is 100

    需要注意两点:

    1. 函数一结束就要取返回值,以免被其他命令执行结果覆盖了当前函数的返回值
    2. 退出状态码取值范围0~255

    为什么$?取值不能大于255

    答案:https://baijiahao.baidu.com/s?id=1592296182804783596&wfr=spider&for=pc

    使用函数输出

    使用$(函数名)或者`函数名`获取函数的输出

    这里书中有误把反引号打成单引号

    [root@tzPC 17Unit]# bash test5b.sh 
    Enter a value: 200
    Enter a value: 200
    The new value is 400 and 400
    [root@tzPC 17Unit]# cat test5b.sh 
    #!/bin/bash
    #using the echo to return a value
    function db1 { 
        read -p "Enter a value: " value
        echo $[ value * 2 ]
    }
    
    result=`db1`
    result2=$(db1)
    echo "The new value is $result and $result2"

    向函数传递参数

    函数可以使用标准的参数环境变量表示命令行上传给函数的参数。

    如函数命令行上的任何参数都可以通过$1、$2定义,$#判断函数参数的总数

    必须把参数和函数放在同一行上,如

    funcl $value1 10

    举例

    [root@tzPC 17Unit]# cat test6.sh
    #!/bin/bash
    #passing parameters to a function
    function addem {
        if [ $# -eq 0 ] || [ $# -gt 2 ]
        then
            echo -1
        elif [ $# -eq 1 ]
        then 
            echo $[ $1 + $1 ]
        else
            echo $[ $1 + $2 ]
        fi
    }
    
    echo -n "Adding 10 and 15: "
    #传递两个参数,函数使他相加
    value=$(addem 10 15)
    echo $value
    
    echo -n "Let's try adding just one number: "
    #传递一个参数,函数使他自己加自己
    value=$(addem)
    echo $value
    echo -n "Finally, try adding three numbers: "
    value=$(addem 10 15 20)
    #传递三个参数,函数直接输出-1
    echo $value
    
    [root@tzPC 17Unit]# bash test6.sh
    Adding 10 and 15: 25
    Let's try adding just one number: -1
    Finally, try adding three numbers: -1

    在函数中使用脚本传递过来的参数

    [root@tzPC 17Unit]# cat test7.sh 
    #!/bin/bash
    #trying to access script parameters inside a function
    function func7 {
        echo $[ $1 * $2 ]
    }
    
    if [ $# -eq 2 ]
    then 
        value=$(func7 $1 $2)
    #传递脚本命令行上的参数
        echo "The result is $value"
    else
        echo "Usage: badtest1 a b"
    fi
    
    [root@tzPC 17Unit]# bash test7.sh 10 15
    The result is 150

    在函数中处理变量

    函数中使用两种类型的变量

    • 全局变量
    • 局部变量

    全局变量是shell脚本中任何地方都有效的变量。

    默认情况下,在脚本中定义的任何变量都是全局变量。在函数外定义的变量可在函数内访问。

    局部变量是函数内部使用的变量,声明格式如下

    local temp
    local temp=$[ $value + 5 ]

    这样如果脚本中在该函数之外有同样名字的变量,他们的值是不会影响到对方的。

    [root@tzPC 17Unit]# cat test9.sh
    #!/bin/bash
    #demonstrating the local keyword
    function func1 {
        local temp=$[ $value + 5 ]
        result=$[ $temp * 2 ]
    }
    
    temp=4
    value=6
    
    func1
    #调用函数
    echo "The result is $result"
    if [ $temp -gt $value ]
    #这里的值使用的是函数外定义的值即4>6
    then
        echo "temp is larger"
    else
        echo "temp is smaller"
    fi
        
    [root@tzPC 17Unit]# bash test9.sh
    The result is 22
    temp is smaller

    向函数传数组

    如果把数组直接作为函数参数,函数只会读取数组变量的第一个值。

    这个脚本在书中有两处错误,具体写法如下

    [root@tzPC 17Unit]# cat test10.sh
    #!/bin/bash
    #array variable to function test
    function testit {
        local newarray
        newarray=`echo "$@"`
    #接收传来的参数全部赋值给局部变量newarray,注意这里是反引号
    #也可以写成newarray=$(echo "$@")
    echo "The new array value is: ${newarray[*]}" } myarray=(1 2 3 4 5) echo "The original array is ${myarray[*]}"
    #${myarray[*]}的值是 1 2 3 4 5 testit ${myarray[*]}
    #向函数传递数组的值,也就是1 2 3 4 5 [root@tzPC 17Unit]# bash test10.
    sh The original array is 1 2 3 4 5 The new array value is: 1 2 3 4 5

    也可以在函数中通过遍历累加数组

    [root@tzPC 17Unit]# cat test11.sh 
    #!/bin/bash
    #adding values in an array
    function addarray {
        local sum=0
        local newarray
        newarray=$(echo "$@")
    #这里也可以写成newarray=`echo "$@"`
    for value in ${newarray[*]}
    do
        sum=$[ $sum + $value ]
    #将数组的值遍历出来相加
    done
    echo $sum
    
    }
    
    myarray=(1 2 3 4 5)
    echo "The original array is: ${myarray[*]}"
    arg1=$(echo ${myarray[*]})
    #将1 2 3 4 5赋值给arg1变量
    echo $arg1
    result=$(addarray $arg1)
    echo "The result is $result" 
    [root@tzPC 17Unit]# bash test11.sh 
    The original array is: 1 2 3 4 5
    1 2 3 4 5
    The result is 15

    从函数返回数组

    将数组传进函数,再从函数做运算在传回脚本

    #这里的例子书中有个小错误,应如下写法

    [root@tzPC 17Unit]# cat test12.sh 
    #!/bin/bash
    #returning an array value
    function arraydblr {
        local origarray
        local newarray
        local elements
        local i
        origarray=($(echo "$@"))
        newarray=($(echo "$@"))
        elements=$[ $# - 1 ]
        for (( i=0;i<=$elements;i++ ))
        do
            newarray[$i]=$[ ${origarray[$i]}*2 ]
        done
        echo ${newarray[*]}
    
    }
    
    myarray=(1 2 3 4 5)
    echo "The original array is: ${myarray[*]}"
    arg1=$(echo ${myarray[*]})
    #此时arg1的值为1 2 3 4 5
    result=($(arraydblr $arg1))
    echo "The new array is: ${result[*]}"

    #执行结果
    [root@tzPC 17Unit]# bash test12.sh The original array is: 1 2 3 4 5 The new array is: 2 4 6 8 10

    函数递归

    函数可以自己调用自己

    例:计算阶乘,一个数的阶乘是该数之前所有数乘以该数的值,比如计算5的阶乘,如下

    5!=1*2*3*4*5

    =120

    公式为x!=x*(x-1)

    好吧,我卡在这个例子了,没弄懂

    [root@tzPC 17Unit]# cat test13.sh
    #!/bin/bash
    #using recursion
    function factorial {
        if [ $1 -eq 1 ]
        then
            echo 1 #1的阶乘为1
        else
            local temp=$[ $1 -1 ]
            local result=$(factorial $temp)
            echo  $[ $result*$1 ]
        fi
    }
    read -p "Enter value: " value
    result=$(factorial $value)
     echo "The factorial of $value is: $result"
    [root@tzPC 17Unit]# bash test13.sh
    Enter value: 5
    The factorial of 5 is: 120

     创建库

    方便在多个脚本中使用同一段代码,这段代码就叫做函数库文件,相当于类。

    创建名为myfuncs的函数库

    [root@tzPC 17Unit]# cat myfuncs 
    #my script functions
    function addem {
        echo $[ $1 + $2 ]
    }
    
    function multem {
        echo $[ $1 * $2 ]
    }
    
    function divem {
        if [ $2 -ne 0 ]
        then
            echo $[ $1 / $2 ]
        else
            echo -1
        fi
    }

     将函数库文件添加到脚本中

    这里要用到.跟source命令,因为运行脚本会在当前Shell中创建子Shell运行脚本,使用这两个命令会使脚本在当前shell中运行。

    [root@tzPC 17Unit]# cat test14.sh
    #!/bin/bash
    #using functions defined in a library file
    . ./myfuncs
    
    value1=10
    value2=5
    result1=$(addem $value1 $value2)
    result2=$(multem $value1 $value2)
    result3=$(divem $value1 $value2)
    echo "The result of adding them is: $result1"
    echo "The result of multiplying them is: $result2"
    echo "The result of dividing them is: $result3"
    
    [root@tzPC 17Unit]# bash test14.sh
    The result of adding them is: 15
    The result of multiplying them is: 50
    The result of dividing them is: 2

    在命令行中使用函数

    在命令行上创建函数,缺点是退出shell时,函数就消失了

    单行定义函数

    [root@tzPC 17Unit]# function divem { echo $[ $1 /$2 ]; }
    [root@tzPC 17Unit]# divem 100 5
    20

    多条命令必须在后面加个分号分隔

    [root@tzPC 17Unit]# function doubleit { read -p "Enter value: " value; echo $[ $value *2 ]; }
    [root@tzPC 17Unit]# doubleit
    Enter value: 20
    40

    多行方式定义函数

    [root@tzPC 17Unit]# function multem {
    > echo $[ $1 * $2 ]
    > }
    [root@tzPC 17Unit]# multem 2 5
    10

    在.bashrc文件中定义函数

    每次bash shell启动时自动加载~/.bashrc文件,可以在在此定义函数,或调用指定函数库文件路径。

    [root@tzPC ~]# cat ~/.bashrc 
    # .bashrc
    
    # User specific aliases and functions
    
    alias rm='rm -i'
    alias cp='cp -i'
    alias mv='mv -i'
    
    # Source global definitions
    if [ -f /etc/bashrc ]; then
        . /etc/bashrc
    fi
    echo "123"
    . /root/script/17Unit/myfuncs

    下次bash shell启动时,就能在命令行界面使用定义的函数了

    [root@tzPC ~]# addem 10 5
    15
    [root@tzPC ~]# multem 10 5
    50
    [root@tzPC ~]# divem 10 5
    2

    同样子shell也能调用此函数库文件

    使用GNU shtool shell库

    不止自己定义函数使用,还可以下载网上别人定义的函数用于自己的脚本中。

    shtool库提供了一些简单的shell脚本函数,可用来完成日常的shell功能,如处理临时文件、目录或格式化输出

    同样也可以在网上下载别人写的脚本,根据需求改一下自己使用

    下载安装

    浏览器中输入

    ftp://ftp.gnu.org/gnu/shtool/

     我这里下载的是书中案例2.0.8版本

    在浏览器中输入

    ftp://ftp.gnu.org/gnu/shtool/shtool-2.0.0.tar.gz

    下载完成后使用rz命令上传到服务器中

    使用tar命令提取文件

    [root@tzPC 17Unit]# tar -zxvf shtool-2.0.0.tar.gz

    构建库

    configure命令会检查构建shtool库文件所需要的工具,并将其路径修改到shtool配置文件中。

    [root@tzPC shtool-2.0.0]# ./configure 
    Configuring GNU shtool (Portable Shell Tool), version 2.0.0 (02-Jul-2004)
    Copyright (c) 1994-2004 Ralf S. Engelschall <rse@engelschall.com>
    checking whether make sets $(MAKE)... yes
    checking for perl interpreter... /usr/bin/perl
    checking for pod2man conversion tool... /usr/bin/pod2man
    configure: creating ./config.status
    config.status: creating Makefile
    config.status: creating shtoolize
    config.status: executing adjustment commands

     make命令用于构建shtool库文件

    使用make测试库文件中的函数是否正常运行

    [root@tzPC shtool-2.0.0]# make test
    Running test suite:
    echo...........ok
    mdate..........ok
    table..........ok
    prop...........ok
    move...........ok
    install........ok
    mkdir..........ok
    mkln...........ok
    mkshadow.......ok
    fixperm........ok
    rotate.........ok
    tarball........ok
    subst..........ok
    platform.......ok
    arx............ok
    slo............ok
    scpp...........ok
    version........ok
    path...........ok
    OK: passed: 19/19

    以root运行make install选项安装shtool库

    [root@tzPC shtool-2.0.0]# make install 1>/dev/null&& echo ok
    ok

    安装完成就能在Shell脚本中使用这些函数了

    shtool库函数

    各函数介绍,书P376

    shtool函数包含选项和参数,用于更改函数工作方式。

    语法格式

    shtool [options] [function [options] [args]]

    使用库

    在命令行中使用

    [root@tzPC shtool-2.0.0]# shtool platform
    centos 7.4.1708 (AMD64)

    在脚本中使用

    [root@tzPC shtool-2.0.0]# cat test16.sh
    #!/bin/bash
    shtool platform
    [root@tzPC shtool-2.0.0]# bash test16.sh 
    centos 7.4.1708 (AMD64)

     prop函数可以创建一个旋转进度条,可以玩玩

    [root@tzPC 17Unit]# bash test15.sh | shtool prop -p "waiting..."
    waiting....

    学习来自:《Linux命令行与Shell脚本大全 第3版》第17章

    今天的学习是为了以后的工作更加的轻松!
  • 相关阅读:
    BZOJ2762: [JLOI2011]不等式组
    BZOJ1452: [JSOI2009]Count
    Codeforces Round #441 (Div. 2, by Moscow Team Olympiad)
    BZOJ1635: [Usaco2007 Jan]Tallest Cow 最高的牛
    BZOJ2730: [HNOI2012]矿场搭建
    Flask实现异步非阻塞请求功能
    在flask中使用websocket-实时消息推送
    Python数据库连接池DBUtils
    flask请求上下文
    scanf与getchar
  • 原文地址:https://www.cnblogs.com/tz90/p/13543752.html
Copyright © 2020-2023  润新知