Burnov

导航

创建函数

  在shell脚本编写中,通常有很多处使用相同的代码。如果这些代码比较短小,name通常并不费事。但是,如果有打断代码需要重写,则会让人厌烦,这个我们就需要使用函数来处理;

1、基本脚本函数

  函数是被富裕名称的脚本代码块,可以在代码的任意位置重复使用。引用函数的过程,我们称之为调用;

  1.1、创建函数

    在bash shell脚本中创建函数可以使用两种格式:

function name {  #name为唯一名称
    commands    #commands为组成函数功能的命令
}

    另外一种格式

name() {
commands
}

  1.2、使用函数

    相应的函数名需要在脚本中指定

#!/bin/bash
# using a function in a script

function func1 {
    echo "This is an example of a funcation"
}

count=1
while [ $count -le 5 ]
do
    func1
    count=$[ $count + 1 ]
done
echo "This is the end of the loop"
func1
echo "Now this is the end of the script"

    注意,不能在函数被定义之前去调用这个函数,会报错

#!/bin/bash
# using a function located in the middle of a script

count=1
echo "This line comes before the function definition"

function func1 {
    echo "This is an example of a function"
}

while [ $count -le 5 ]
do
    func1
    count=$[ $count + 1 ]
done
echo "This is the end of the loop"
func2  #没有定义func2,所以这里会报错
echo "Now this is the end of the script"

    函数的命名也需要注意,必须唯一。如果重新定义了函数,则新定义的函数就会覆盖原来的函数

#!/bin/bash
# testing using a duplicate function name

function func1 {
    echo "This is first definition of the function name"
}

func1

function func1 {  #新定义的函数就会覆盖原来的函数
    echo "This is a repeat of the same function name"
}

func1
echo "This is the end of the script"

2、返回值

  bash shell将函数看成小型的脚本,并以退出转态结束。函数退出转态有三种生成方式;

  2.1、默认退出状态

    函数的退出转态是函数的最后一条命令返回的退出状态 。可以$?来确定函数的退出状态;

#!/bin/bash
# testing the exit status of a function

func1 () {
    echo "Trying to display a non-existend file"
    ls -l badfile
}

echo "testing the function:"
func1
echo "The exit status is: $?"

    这样可以知道函数执行转态为1,但是无法知道其他命令是否执行成功。

#!/bin/bash
# testing the exit status of a function

func1 () {
    ls -l badfile
    echo "This was a test of a bad command"
}

echo "testing the functiong:"
func1
echo "The exit status is: $?"

    因为函数中命令位置变换,则返回的函数转态值就是0了;所以这种方式来判断函数是不正确的;

  2.2、使用return命令

    所以,我们引入了return命令来指定函数转态。return命令可以使用单个整数值来定义函数退出转态,提供了一种通过编辑设置函数退出转态的简单方法;

#!/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函数将变量$value中的用户输入值变为双倍后,通过return返回
}

db1
echo "The new value is $?"

    注意两点:1、函数完成后尽快提取返回值;2、退出转态的取值范围是0-255;

  2.3、使用函数输出

    函数输出的结果可以给变量赋值:

    result=`db1`

    这样db1函数的值,就给了$result中

#!/bin/bash
# using the echo to return a value

function db1 {
    read -p "Enter a value: " value
    echo $[ $value * 2 ]
}

result=`db1`
echo "The new value is $result"

    这个函数使用echo语句显示计算结果,获取了db1的输出,而不是查看命令运行的状态结果;

3、在函数中使用变量

  上一个函数中的$value就是函数变量使用的方法之一,在函数中要注意变量调用;

  3.1、向函数传递参数

    $1 $2 $# 如何传递给函数呢?

#!/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 10`
echo $value
echo -n "Now trying adding no numbers: "
value=`addem`
echo $value
echo -n "Finally, try adding three numbers: "
value=`addem 10 15 20`
echo $value

    由于函数为自己的参数值使用专用的参数环境变量,所以函数无法从脚本命令行直接范文脚本参数值。下面的例子就是一个错误的例子:

#!/bin/bash
# trying to access script parameters inside a function

function badfunc1 {
    echo $[ $1 * $2 ]
}

if [ $# -eq 2 ]
then 
    value=`badfunc1`
    echo "The result is $value"
else
    echo "Usage: badtest1 a b"
fi
./badtest1 10 15
./badtest1: * : syntax error: operand expected (error token is "*")

    该函数使用管道变量$1和$2,不同于脚本主代码的变量$1和$2.如果想在函数中使用这些值,那么必须在调用该函数时手动传递这些数据:

#!/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

  3.2、在函数中处理变量

    函数中使用两种变量:1、全局变量;2、局部变量;

    1、全局变量

    shell脚本中全部地方都会生效

#!/bin/bash
# using a global variable to pass avalue

function db1 {
    value=$[ $value * 2 ]
}

read -p "Enter a value: " value
db1
echo "The new value is: $value"

    $value在函数外部复制,同时在函数内部使用,依然生效。

    郑重做法要求程序员确切的清除函数中使用了那些变量,包括那些勇于计算值且不返回脚本的所有变量。

#!/bin/bash
# demonstrating a bad use of variables

function func1 {
    temp=$[ $value + 5 ]
    result=$[ $temp * 2 ]
}

temp=4
value=6

func1
echo "The result is $result"
if [ $temp -gt $value ]
then
    echo "temp is larger"
else
    echo "temp is smaller"
fi

    这种情况下,temp又在函数外部赋值,又在行数内部使用,所以结果可能会出人意料

    2、局部变量

    local 代表局部变量:local temp

    local temp=$[ $value + 5 ]

    local变量仅仅在函数内部使用;

#!/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 ]
then
    echo "temp is larger"
else
    echo "temp is smaller"
fi

    这样,func1内部使用变量$temp时,脚本主代码变量$temp的值不会受到映像

4、数组变量与函数

  函数使用数组变量值需要一些技巧。

  4.1、向函数传递数组

    如果试图将数组变量作为单个参数传递,是无法正常工作的:

#!/bin/bash
# trying to pass an array variable

function testit {
    echo "The parameters are: $@"
    this array=$1
    echo "The received array is ${thisarray[*]}"
}

myarray={1 2 3 4 5}
echo "The original array is: ${myarray[*]}"
testit $myarray

    这时候,函数只能提取数组的一个值。

    要解决这个问题,必须将数组变量拆分为单个元素,然后使用这些元素的值作为函数参数。

#!/bin/bash
# array variable to function test

function testit {
    local newarray
    newarray=(`echo "$@"`)
    echo "The new array value is: ${newarray[*]}"
}

myarray=(1 2 3 4 5)
echo "The original array is ${myarray[*]}"
testit ${myarray[*]}

    这时候myarray[*]就能存放数组所有的值了;函数内部可以像使用其他素组一样使用这个数组;

#!/bin/bash
# adding values in an array

function addarray {
    local sum=0
    local newarray
    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=`The original array is: ${myarray[*]}`
result=`addarray $arg1`
echo "The result is $result"

  4.2、从函数返回数组

    使用echo语句以恰当顺序输出数组元素之,然后脚本必须将这些数据重组为新数组变量;

#!/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++ ))
    {
        newarray[$i]=[ ${origarray[$i]} * 2 ]
    }
    echo ${newarray[*]}
}

myarray=(1 2 3 4 5)
echo "The original array is: ${myarray[*]}"
arg1=`echo ${myarray[*]}`
result=(`arraydblr $arg1`)
echo "The new array is: ${result[*]}"
./test12
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)!

  这就可以以脚本的形式展现出来:

function factorial {
    if [ $1 -eq 1 ]
    then
        echo 1
    else
        local temp=$[ $1 - 1 ]
        local result=`factorial $temp`
        echo $[ $result * $1 ]
    fi
}

  该阶乘函数调用自身进行计算:

#!/bin/bash
# using recursion

function factorial {
    if [ $1 -eq 1 ]
    then
        echo 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"

6、创建库

  多个脚本使用同样的函数,这时候我们就需要创建库文件才行;

# 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
}

  下一步将这个文件包含进需要调研的库函数中

  问题:如果从shell命令行界面运行myfuncs脚本,nameshell将打开一个新shell,并在该新shell中运行脚本。这将为新shell定义3个函数,但是当试图运行调用这些函数的另一个脚本时,库函数并不使用;

#!/bin/bash
# using a library file the wrong way
./myfuncs

result=`addem 10 50`
echo "The result is $result"

  使用函数库的关键命令时source命令。使用source命令再shell脚本内部运行库文件脚本。这样脚本就可以使用这些函数。

#!/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"

7、在命令行中使用函数

  函数可以使用在外面命令行中

  7.1、在命令行创建函数

    两种方法:

    1、将函数定义在一行命令中:

    $ function divem { echo $[ $1 / $2 ]; }

    $ divem 100 5

    在命令行中定义函数,每条命令后面必须用分号隔开;

    $ funtion doubleit { read -p "Enter value: " value; echo $[ $value * 2 ]; }

    $ doubleit

    2、使用多行命令定义函数。这样,bash shell使用次级命令提示符输入更多的命令

    $ function multem {

    > echo $[ $1 * $2 ]

    > }

    $ multem 2 5

    10

    $

  7.2、在.bashrc文件中定义函数

    在命令行下定义函数,一退出,就不能继续运行了。所以我们可以在.bashrc文件中来定义;

    1、直接定义函数

$ cat .bashrc
# .bashrc

# Source global definitions
if [ -r /etc/bashrc ]; then
        . /etc/bashrc
fi

function addem {
echo $[ $1 + $2 ]
}

    2、提供函数文件

    正如shell脚本中的做法一样,可以使用source命令(点操作符),将库文件的函数包含进.bashrc脚本:

$ cat .bashrc
# .bashrc

# Source global definitions
if [ -r /etc/bashrc ]; then
        . /etc/bashrc
fi

. /home/rich/libraries/myfuncs

    确保库文件的准确路径,这样bash shell才能够找到库文件。再次启动shell之后,该库的所有函数将都能在命令行界面使用;

    更好的是,shell还将全部已定义函数传递给子shell进程。这样从shell会话运行的脚本,自定义函数随之可用。

#!/bin/bash
# using a function defined in the .bashrc file

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"

 

    

posted on 2019-05-01 07:40  Burnov  阅读(398)  评论(2编辑  收藏  举报