在bash中是支持函数编写的,函数的作用就不言而喻了-一次定义,多处调用。调用函数时,只需输入给它的函数名即可。

我们将讨论如何创建自己的bash函数以及如何在shell脚本中使用它们。

一、创建函数

定义函数格式:

functioName() {

}

我们也可以使用fucntion关键字来定义,但考虑posix可移植性,不推荐使用该关键字。

function name() {

}

二、使用函数

myfunc() {
 echo "我正在使用函数..."
}
total=1
while [ $total -le 3 ];do
    myfunc
    total=$(($total+1))
done
echo "结束循环"
myfunc
echo "结束脚本"

我们执行该脚本,输出结果如下:

我正在使用函数...
我正在使用函数...
我正在使用函数...
结束循环
我正在使用函数...
结束脚本

如果我们调用未定义的函数时,将会报错comand not found,但脚本依然可以执行到尾行。

我们用两种方式定义函数,函数名相同,如下:

#!/bin/bash

myfunc() {
    echo "The first function definition"
}

myfunc

function myfunc() {
    echo "The second function definition"
}

myfunc
echo "End of the script"

上述代码,function定义的函数名与第一种方式同名,它们不会报错,后定义的会覆盖掉先前定义的。执行结果如下:

The first function definition
The second function definition
End of the script

三、使用函数返回值

我们有两种方式来使用函数的返回值,我们先看第一种:

#!/bin/bash
myfunc() {
read -p "请输入一个数字:" value
 echo "正在操作"
 return $(($value+100))
}
myfunc
echo "新的value值为: $?"

我们执行它:

sh demo.sh
请输入一个数字:99
正在操作
新的value值为: 199

由此我们看出,函数的返回值为执行上一个命令的状态码,即return值为状态码。

如果我们返回值不是数字,是字符串会怎么样?

myfunc(){
  return 'hello' 
}
#调用函数
myfunc
echo "新的value值为: $?"

line 5: return: hello: numeric argument required
新的value值为: 255

上述代码我们看到,函数内不允许返回字符串,返回字符串时,状态码为 255

注意:使用return作为返回值,最大值不能超过255,状态码最大值为255,表示状态码越界。

第二种方式使用函数返回值:

#!/bin/bash
myfunc() {
read -p "请输入一个数字:" value
 echo "正在操作"
 echo $(($value+100))
}
result=$(myfunc)
echo $result

注意:函数体内,我们使用了echo,并不是return,这时我们可以将函数名作为变量名使用。

四、传递参数

我们可以使用类似环境变量形式为函数传递参数。函数名声明为$0变量,传递的参数为$1、$2、$3等。

示例:

#!/bin/bash

addnum() {

    if [ $# -gt 2 ]; then  # $#表示参数个数

        echo "请输入两个参数"

    else

        echo $(($1 + $2))

    fi

}
echo  "10 + 15: "

value=$(addnum 10 15)

echo $value
# 24

echo "测试三个参数:"

value=$(addnum 10 15 20)

echo $value
#请输入两个参数

当我们输入三个参数时,会提示我们输入两个参数。

我们来看一个错误示例:

#!/bin/bash

myfunc() {

    echo $(($1 + $2 + $3 + $4))

}

if [ $# -eq 4 ]; then

    value=$(myfunc)

    echo "Total= $value"

else

    echo "请按照右边形式调用: myfunc a b c d"

fi

我们执行上述代码:sh demo.sh 1 2 3 4,我们传入了四个参数,查看结果:

demo.sh: line 5: +  +  + : syntax error: operand expected (error token is " ")
Total=

代码执行错误,我们在执行demo.sh时虽然传入了四个参数,但是在脚本中,我们想使用函数的返回值,但是在调用函数时,并未传入我们在执行脚本时的参数 ,导致函数体内的$1...未定义。

我们改造一下 再调用sh demo.sh 1 2 3 4

#!/bin/bash

myfunc() {

    echo $(($1 + $2 + $3 + $4))

}

if [ $# -eq 4 ]; then

    value=$(myfunc $1 $2 $3 $4) #改造的代码

    echo "Total= $value"

else

    echo "请按照右边形式调用: myfunc a b c d"

fi

#执行结果为:Total =10

正确输出结果 10

五、在函数内使用变量

我们可以定义两种变量 :globallocal

我们先看global,默认情况下,声明的任何变量都是全局变量。如果在函数之外定义变量,则在函数内调用它没有问题。

#!/bin/bash

myfunc() {

    input=$(($input + 10))

}

read -p "请输入一个数字: " input

myfunc

echo "新的数字为: $input"

#我们输入数字 5,执行结果为 15

上述代码,我们执行脚本,然后输入数字 5,执行结果为15。在函数内部可以访问到外部的input,并且外部的变量被更改为 15

local变量使用:

#!/bin/bash

myfunc() {

    local tmp=10
    echo "函数内值: $tmp"
}

tmp=4

myfunc

echo "函数外值: $tmp"

函数内值: 10
函数外值: 4

我们在函数内部和外部定义了同名的两个变量,但结果互不影响。

六、使用数组作为函数参数

#!/bin/bash

myfunc() {

    echo "所有参数: $@"

    echo $1
    echo $2
    echo $3

}

my_arr=(5 10 15)

echo "原始数组的值为: ${my_arr[*]}"
myfunc ${my_arr[*]}

#执行结果
原始数组的值为: 5 10 15
所有参数: 5 10 15
5
10
15

我们将数组内所有值传递给函数,在函数内可以全部获取到数组内的值。

七、递归调用:

我们编写一个例子,实现某个数字的阶乘。

myfucn(){
  if [ $1 -eq 1 ];then
    echo 1
  else
    local next=$[$1-1]
    local res=$(myfucn $next)
    echo $(($res * $1))
  fi
}

myfucn 5
#120

八、作为库文件被外部引用

我们编写A文件如下:

#!/bin/bash
addnum() {
  echo $(($1 + $2))
}

编写B文件,并在B文件引入A:

#!/bin/bash
. ./A
echo $(addnum 10 20)
#输出结果 30

我们还可以将A文件的addnum作为一条命令来执行,首先我们编辑家目录里的.bashrc文件,我们加入一行:

. /Users/houger/A

注意:开始位置有个点.,不要省略掉,它的意思是加载脚本文件

接下来我们执行命令:addnum 10 20 ,正确执行,输出结果30

参考:

Bash Scripting

往期:

shell 的入门学习笔记第一篇

shell中流程控制语法的第二篇

shell中读取命令行参数第三篇


Leave Your Comment

电子邮件地址不会被公开。 必填项已用*标注