前置知识要求
- Linux 命令行基础
- Shell 编程基础概念
如何创建一个函数
方式一:
#!/usr/bin/env bash
function myFunc {
commands
}
方式二:
#!/usr/bin/env bash
myFunc () {
commands
}
myFunc
是函数的名字,脚本中定义的每个函数都必须有一个唯一的名称。
如果有多个同名的函数,那么后面的定义就会覆盖前面的,更重要的是这一切不会产生任何错误!!!
如何调用一个函数
#!/usr/bin/env bash
function myFunc {
echo "This is our first function demo."
}
# 直接使用函数名即可,就像调用其他 shell 命令一样
myFunc
必须在函数被定义之后,才可以使用这个函数,不然会报错“command not found”
如何在函数中定义局部变量
默认情况下,在脚本中定义的变量都是全部变量。在函数外定义的变量都可在函数内部随意使用。同样地,在函数内部定义的全局变量,也可以在脚本其他地方读写。
这样太混乱且不安全,所以我们需要一种方式能够在函数内部定义局部变量。这个方式就是 bash shell 提供的 local
命令。
#!/usr/bin/env bash
top="top"
function testLocalVar {
# global variable
ridge="ridge"
# local variable
local regional="regional"
echo "function interior, access global variable 'top': $top"
echo "function interior, access local variable 'regional': $regional"
}
testLocalVar
echo
echo "script top, access global variable 'ridge' defined in function: $ridge"
echo "script top, access function interior local variable 'regional': $regional"
如何向函数传参
bash shell 会将函数当作小型脚本来对待。所以我们可以像普通脚本那样向函数传递参数。 也就是说,函数可以使用标准的环境变量参数来表示传给函数的参数:
$0
:函数名字$1
:函数的第1个实参$2
:函数的第2个实参$#
:函数的实参个数$*
:函数的所有参数当作一个单词保存(将这些参数视为一个整体而不是多个独立的个体)$@
:函数的所有参数当作同一字符串中的多个独立的单词
#!/usr/bin/env bash
function printName {
echo "Hello $1"
}
user="juejin"
# 调用时实参必须和函数名字放在同一行:
printName $user
如何向函数传递脚本命令行中的参数值
#!/usr/bin/env bash
function printCommandLineParams {
echo "the first parm from command line input is: $1"
}
# 手动地将脚本中的特殊环境变量参数传递给函数即可
printName $1
如何向函数传递数组呢
很遗憾,在 Bash 中不能将数组变量当作单个参数传递给函数;要想实现这一点,我们只能是将数组展开,然后在函数内部再依此创建一个新的数组。
#!/usr/bin/env bash
function printArray {
newArr=("$@")
echo "${newArr[*]}"
}
aArr=(1 2 3 4 5)
printArray "${aArr[*]}"
如何从函数中返回值
函数的退出状态码
bash shell 会把函数当作一个小型脚本,运行结束时会返回一个状态码。默认情况下,函数的退出状态码是函数中最后一条命令返回的退出状态码。在函数执行结束后,可以使用标准变量 $?
来确定函数的退出状态码。
#!/usr/bin/env bash
function testStatusCode {
ls -l non-existent
echo "trying to display a non-existent file"
}
testStatusCode
echo "The exit code status is: $?"
上面代码,函数中最后一条命令执行成功,所以函数的退出状态码是 0,即使函数内部有执行出错的命令。
return 命令
bash shell 使用 return
命令来退出函数并返回特定的退出状态码。return
命令允许指定一个整数值来定义函数的退出状态码。
#!/usr/bin/env bash
function customStatusCode {
return $(( value * 2 ))
}
value=3
x=$(customStatusCode $value)
echo "The new value is $?"
echo "The x is $x"
可以看到,return
命令自定义的状态码只能通过 $?
参数来获取,而且也没法向外输出值。
而且使用这种方式获取值,还有 2 个问题:
- 必须在函数一结束就获取
$?
的值 return
命令的值必须是 0~255
如果在使用 $?
变量值之前执行了其他命令,那么 return
命令的值就会丢失。而如果 return
的值不在[0, 255]
之间,会产生一个错误值。
echo 输出
为了将函数内部的数据值向外部输出,我们可以在函数内部的最后使用 echo
命令,然后在外部使用变量保存函数输出的这个值即可:
#!/usr/bin/env bash
function add {
echo $(( $1 + $2 ))
}
first=1
second=2
sum=$(add $first $second)
echo "the sum of $first and $second is: $sum"
这种方式也是有问题的,如果函数内部有多个 echo
:
#!/usr/bin/env bash
function add {
echo "Hi~I'm add function"
echo $(( $1 + $2 ))
}
first=1
second=2
sum=$(add $first $second)
echo "the sum of $first and $second is: $sum"
echo 输出数组
正如同向函数传递数组参数那样,在 Shell 脚本中,没法将一个数组变量作为单个变量值输出。能做的只是在函数内部按照正确顺序输出数组中的每个值,然后在函数外部将这些值重新组装为一个数组。
#!/usr/bin/env bash
function outputArr {
local originalArr=("$@")
local newArr=("$@")
local len=$#
local i=0
while [ "$i" -lt "$len" ]
do
newArr[$i]=$(( ${originalArr[$i]} * 2 ))
i=$(( i + 1 ))
done
echo "${newArr[*]}"
}
myArr=(1 2 3)
result=($(outputArr ${myArr[*]}))
echo "The new Arr is : ${result[*]}"
如何实现递归
这是一个 Bash Script 实现的求阶乘函数:
#!/usr/bin/env bash
function factorial {
if [ $1 -eq 1 ]
then
echo 1
else
local temp=$(( $1 - 1 ))
local result=$(factorial $temp)
echo $(( $1 * $result ))
fi
}
如何使用另一个脚本中的函数
使用 source
命令,我们可以在当前 Shell 上下文中执行命令,而不是创建一个新的 shell。
#!/usr/bin/env bash
# 假设 utils.sh 文件与当前脚本在同一目录下
source ./utils.sh
# 在上面这行命令之后,我们接下来便可以使用 utils.sh 中定义的函数了
source
命令的别名
source命令有个快捷的别名,称作点操作符,之前的例子可以改写为:
#!/usr/bin/env bash
# 假设 utils.sh 文件与当前脚本在同一目录下
. ./utils.sh
# 在上面这行命令之后,我们接下来便可以使用 utils.sh 中定义的函数了
参考
- Richard Blum & Christine Bresnahan.《Linux命令行与shell脚本编程大全(第3版)》.北京:人民邮电出版社.2016