shell 创建函数

1. 脚本函数

函数是一个脚本代码块,你可以为其命名并在代码中任何位置重用。要在脚本中使用该代码块时,只要使用所起的函数名即可,这个过程称为调用函数

采用关键字 function 来创建函数,关键字后跟随分配给该代码块的函数名。

function name {
    commands
}

或通过以下方式来创建函数,函数名后的 空括号 表明正在定义的是一个函数。

name() {
    commands
}

2. 调用函数

在脚本中调用函数,只需要像其他 shell 命令一样,在行中指定需要调用的函数名即可。
注意,如果在函数被定义前调用函数,shell 会提示一条错误消息:This line comes before the function definition
注意,函数名必须是唯一的,否则也会有问题。如果你重定义了函数,新定义会覆盖原来函数的定义,这一切不会产生任何错误消息。

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

fun
This is an example of a function

3. 函数的返回值

bash shell 会把函数当作一个小型脚本,运行结束时会返回一个退出状态码,有 3 种不同的方法来为函数生成退出状态码。

3.1. 默认退出状态码

默认情况下,函数的退出状态码是函数中最后一条命令返回的退出状态码,命令执行成功退出码为 0,命令执行错误退出码为 1。在函数执行结束后可以用标准变量 $? 来确定函数的退出状态码。

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

fun
echo "The exit status is: $?"
------------------------------------------
The exit status is: 0

存在一个问题

由于函数最后一条语句 echo 运行成功,该函数的退出状态码就是 0 ,尽管其上一条命令并没有正常运行。所以其实使用默认的状态退出码是不准确的。

3.2. 使用 return 命令

bash shell 使用 return 命令来退出函数并返回特定的退出状态码。return 命令允许我们自己主动指定一个整数值来定义函数的退出状态码,从而提供了一种简单的途径来编程设定函数退出状态码 (退出状态码必须是0~255。)。我们同样可以用标准变量 $? 来确定函数的退出状态码。在用 $? 变量提取函数返回值之前执行了其他命令,函数的返回值就会丢失,因为 $? 变量会返回执行的最后一条命令的退出状态码。

由于退出状态码必须小于 256,所以函数的结果必须生成一个小于 256 的整数值。任何大于 256 的值都会产生一个错误值。要返回较大的整数值或者字符串值,或浮点数值的话,你就不能用这种返回值的方法了。

function fun {
	read -p "Enter a value: " value
	echo "Doubling the value"
	return $[ $value * 2 ]
}

fun 
echo "The new value is $?"

3.3. 使用函数输出

我们可以将命令的输出保存到一个 shell 变量中一样,同样也可以对函数的输出采用同样的处理办法。可以用这种技术来获得任何类型的函数输出,并将其保存到变量中:result='fun' 将函数 fun 的返回值保存到变量中。

function fun {
	read -p "Enter a value: " value
	echo $[ $value * 2 ]
}
result=$(fun)
echo "The new value is $result"

**注意:**在这里 echo 命令作用是将函数中的返回值返回,它并不会将数据从终端中直接输出。

4. 在函数中使用变量

前面已经提到过,bash shell 会将函数当作小型脚本来对待。这意味着你可以像普通脚本在脚本名称后面跟随需要传递的参数那样在函数名的后面跟随需要传递的参数来给函数传参。在脚本中指定函数时,必须将参数和函数放在同一行。比如这样 fun $a 10。在函数中我们就可以使用特殊参数来获取我们传递的参数。

fun() {
	echo "$1, $2, $3"
}

shell 特殊变量名表:

360截图20210618235403762.jpg

5. 在函数中处理变量

给 shell 脚本程序员带来麻烦的原因之一就是变量的作用域。作用域是变量可见的区域。函数中定义的变量与普通变量的作用域不同。也就是说,对脚本的其他部分而言,它们是隐藏的。函数使用两种类型的变量:全局变量,局部变量。

5.1. 全局变量

全局变量是在 shell 脚本中任何地方都有效的变量。如果你在脚本的主体部分定义了一个全局变量,那么可以在函数内读取它的值。类似地,如果你在函数内定义了一个全局变量,可以在脚本的主体部分读取它值。默认情况下,你在脚本中定义的任何变量都是全局变量。在函数外定义的变量可在函数内正常访问。

5.2 局部变量

无需在函数中使用全局变量,函数内部使用的任何变量都可以被声明成局部变量。要实现这一点,只要在变量声明的前面加上 local 关键字即可 local i。也可以在变量赋值语句中使用 local 关键字 local i=$[ $a+ 5 ]
local 关键字保证了变量只局限在该函数中。如果脚本中在该函数之外有同样名字的变量,那么 shell 将会保持这两个变量的值是分离的。

6. 在数组变量

注意:向脚本函数传递数组变量的方法会有点不好理解。将数组变量当作单个参数传递的话,它不会起作用,将该数组变量作为函数参数,函数只会取数组变量的第一个值,要解决这个问题,你必须将该数组变量的值分解成单个的值,然后将这些值作为函数参数使用。在函数内部,可以将所有的参数重新组合成一个新的变量。

6.1 数组作为函数参数

数组传递参数存在的问题:

function fun {
	echo "The parameters are: $@"
	arr=$1
	echo "The received array is ${arr[*]}"
}

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

fun $array
-------------------------------------------------
The original array is: 1 2 3 4 5
The parameters are: 1
The received array is 1

解决办法:

function fun {
	local arr
	arr=(;'echo "$@"')![image](https://upload-images.jianshu.io/upload_images/24421677-09876caa9af5b81a.jpg?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)

	echo "The new array value is: ${arr[*]}"
}

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

fun ${array[*]}
-------------------------------------------------------
The original array is 1 2 3 4 5
The new array value is: 1 2 3 4 5

该脚本用 $array 变量来保存所有的数组元素,然后将它们都放在函数的命令行上。该函数随后从命令行参数中重建数组变量。在函数内部,数组仍然可以像其他数组一样使用。

6.2 从函数返回数组

函数里向 shell 脚本返回数组变量也用类似的方法。函数用 echo 语句来按正确顺序输出单个数组值,然后脚本再将它们重新放进一个新的数组变量中。

function fun {
	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=($(fun $arg1))
echo "The new array is: ${result[*]}"
---------------------------------------------------
The original array is: 1 2 3 4 5
The new array is: 2 4 6 8 10

7. 在命令行上使用函数

有时也很有必要在命令行界面的提示符下直接使用函数。让它在 shell 脚本中将脚本函数当命令使用一样,在命令行界面中也可以这样做。在shell 中定义了函数,你就可以在整个系统中使用它了,无需担心脚本是不是在 PATH 环境变量里,重点在于让 shell 能够识别这些函数。

在命令行上创建函数时要特别小心,如果你给函数起了个跟内建命令或另一个命令相同的名字,你定义的函数将会覆盖原来的命令

7.1. 在命令行上创建函数

因为 shell 会解释用户输入的命令,所以可以在命令行上直接定义一个函数。就像下面这样,这里函数被写成了一行。当在命令行上定义函数时,你必须记得在每个命令后面加个分号,这样shell就能知道在哪里是命令的起止了

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

另一种方法是采用多行方式来定义函数。在定义时,bash shell 会使用次提示符来提示输入更多命令。用这种方法,你不用在每条命令的末尾放一个分号,只要按下回车键就行。

$ function multem {
> echo $[ $1 * $2 ]
> }
$ multem 2 5
10

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

在命令行上直接定义 shell 函数的明显缺点是退出 shell 时,函数就消失了。对于复杂的函数来说,这比较麻烦。解决的方法是将函数定义在一个特定的位置,这个位置在每次启动一个新 shell 的时候,都会由 shell 重新载入。最佳地点就是 .bashrc 文件。(.bashrc 文件一般在home/用户文件夹/中,这是一个隐藏文件)bash shell 在每次启动时都会在主目录下查找这个文件不管是交互式 shell 还是从现有 shell 中启动的新 shell。

定义函数

可以直接在主目录下的 .bashrc 文件中定义函数。许多 linux 发行版已经在 .bashrc 文件中定义了一些东西,所以注意不要误删了。把你写的函数放在文件末尾就行了。

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

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

该函数会在下次启动新 bash shell 时生效。随后你就能在系统上任意地方使用这个函数了。

调用函数

了解 source 命令:
source命令也称为点命令,也就是一个点符号(.),是 bash 的内部命令。
功能:使 Shell 读入指定的 Shell 程序文件并依次执行文件中的所有语句,通常用于重新执行刚修改的初始化文件,使之立即生效,而不必注销并重新登录。

只要是在 shell 脚本中,都可以用 source 命令(或者它的别名 . 操作符)将库文件中的函数添加到你的 .bashrc 脚本中。

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

要确保库文件的路径名正确,以便 bash shell 能够找到该文件。下次启动 shell 时,库中的所有函数都可在命令行界面下使用了。更好的是,shell 还会将定义好的函数传给子 shell 进程,这样一来,这些函数就自动能够用于该 shell 会话中的任何shell脚本了。

  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值