函数
和其它“真正”的编程语言一样,Bash也有函数,尽管它在实现方面有一些限制。一个函数就是一个子程序,实现一系列操作的代码块,执行一个特定任务的“黑盒子”。有重复代码的地方,当一个过程只需要轻微修改任务就会重复执行的时候,那么你就需要考虑使用函数了。
# 第一种函数定义, { 可以单独占一行
function function_name () {
# function's body
}
# 第二种函数定义,()可以省略,{ 可以单独占一行
function function_name {
# function's body
}
# 第三种函数定义,function可以省略,{ 可以单独占一行
function_name() {
# function's body
}
一个函数可能被“压缩”到一个单独行里
在这种情况下,函数里的最后一个命令必须跟有一个分号。
fun () { echo "This is a function"; echo } # Error!
fun2 () { echo "Even a single-command function? Yes!"; }
函数调用 就像使用命令一样:
#!/bin/bash
# 定义函数
function my_function() {
echo "Hello from my_function!"
}
# 调用函数
my_function
# 输出其他内容
echo "This is outside the function."
# 再次调用函数
my_function
函数体不能为空 否则会报错,以下空函数会报错syntax error near unexpected token '}'
#!/bin/bash
empty() {
}
empty
函数定义必须在第一次函数调用之前。没有声明函数的方法,比如像C语言中一样:
f1
# 将会产生一个错误消息,因为“f1”函数还没有定义。
declare -f f1 # 这样也不会有帮助。
f1 # 仍然会产生一个错误消息。
# 然而...
f1() {
echo "Calling function \"f2\" from within function \"f1\"."
f2
}
f2 () {
echo "Function \"f2\"."
}
f1 # 在此之前,事实上函数“f2”是没有被调用的,
#+ 尽管在它定义之前被引用了。
# 这是可以的。
# 感谢, S.C.
函数参数
Bash函数支持参数传递function_name arg1 arg2 arg3
,函数体中通过$1,$2,$3
引用arg1,arg2,arg3
。
和其它的编程语言相比,shell脚本一般只会传值给函数。如果把变量名作为参数传递给函数的话,那将被解释为字面含义,也就是被看做字符串。 函数只会以字面含义来解释函数参数。
#!/bin/bash
# func-cmdlinearg.sh
# 带一个命令行参数来执行这个脚本,
#+ 类似于 $0 arg1.
func(){
echo "$1" # 显示传递给这个函数的第一个参数。
} # 命令行参数可以么?
echo "First call to function: no arg passed."
echo "See if command-line arg is seen."
func
# 不! 没有见到命令行参数.
echo "============================================================"
echo
echo "Second call to function: command-line arg passed explicitly."
func $1
# 现在,见到命令行参数了!
exit 0
#!/bin/bash
# 函数和参数
DEFAULT=default # 默认参数值。D
func2 () {
if [ -z "$1" ] # 第一个参数长度是否为零?
then
echo "-Parameter #1 is zero length.-" # 或者没有参数传递进来。
else
echo "-Parameter #1 is \"$1\".-"
fi
variable=${1-$DEFAULT}
echo "variable = $variable" # 这里的参数替换
#+ 表示什么?
# ---------------------------
# 为了区分没有参数的情况
#+ 和只有一个null参数的情况。
if [ "$2" ]
then
echo "-Parameter #2 is \"$2\".-"
fi
return 0
}
echo
echo "Nothing passed."
func2 # 不带参数调用
echo
echo "Zero-length parameter passed."
func2 "" # 使用0长度的参数进行调用
echo
echo "Null parameter passed."
func2 "$uninitialized_param" # 使用未初始化的参数进行调用
echo
echo "One parameter passed."
func2 first # 带一个参数的调用
echo
echo "Two parameters passed."
func2 first second # 带两个参数的调用
echo
echo "\"\" \"second\" passed."
func2 "" second # 第一个调用参数为0长度参数,
echo # 第二个是ASCII码的字符串参数。
exit 0
shift
命令用于移动位置参数
在 Bash 脚本中,shift
命令通常用于移动位置参数(即 $1
、$2
等),使得 $2
的值变为 $1
,$3
的值变为 $2
,依此类推。当在函数中使用 shift
时,它可以用来处理传递给函数的参数列表。
以下是一个使用 shift
命令在 Bash 函数中处理参数的示例:
#!/bin/bash
# 定义一个处理参数的函数
process_args() {
while [[ $# -gt 0 ]]; do
echo "Processing argument: $1"
shift # 移除第一个参数
done
}
# 调用函数并传递参数
process_args arg1 arg2 arg3
在这个示例中,process_args
函数使用了一个 while
循环来检查是否还有参数($# -gt 0
)。如果有参数,它会输出该参数($1
),然后使用 shift
命令移除已经处理过的参数。在 shift
命令执行后,下一个参数(原来的 $2
)就变成了 $1
,依此类推。
输出结果将是:
Processing argument: arg1
Processing argument: arg2
Processing argument: arg3
这个示例展示了如何在 Bash 函数中迭代处理传递给函数的参数列表。shift
命令在每次迭代后移除已经处理过的参数,使得循环能够继续处理剩余的参数。
局部变量
函数内定义的变量默认是全局变量,要想变成局部变量,需要用local关键字声明,那么它就只能够在该变量被声明的代码块中可见。 这个代码块就是局部范围。 在一个函数中,一个局部变量只有在函数代码中才有意义;在函数被调用之前,所有在函数中声明的变量,在函数外部都是不可见的,当然也包括那些被明确声明为local的变量。使用local关键字声明变量是先赋值,然后再限定变量的作用域。下面看一些示例。 局部变量的可见范围:
#!/bin/bash
# ex62.sh: 函数内部的局部变量与全局变量。
func () {
local loc_var=23 # 声明为局部变量。
echo # 使用'local'内建命令
echo "\"loc_var\" in function = $loc_var"
global_var=999 # 没有声明为局部变量。
# 默认为全局变量。
echo "\"global_var\" in function = $global_var"
}
func
# 现在,来看看局部变量“loc_var”在函数外部是否可见。
echo
echo "\"loc_var\" outside function = $loc_var"
# $loc_var outside function =
# 不行, $loc_var 不是全局可见的.
echo "\"global_var\" outside function = $global_var"
# $在函数外部global_var = 999
# $global_var 是全局可见的.
echo
exit 0
# 与C语言相比,在函数内声明的Bash变量
#+ 除非它被明确声明为local时,它才是局部的。
再来看个示例:
#!/bin/bash
function1 ()
{
local func1var=20
echo "Within function1, \$func1var = $func1var."
function2
}
function2 ()
{
echo "Within function2, \$func1var = $func1var."
}
function1
exit 0
# 脚本的输出:
# Within function1, $func1var = 20.
# Within function2, $func1var = 20.
#!/bin/bash
func (){
global_var=37 # 变量只在函数体内可见
#+ 在函数被调用之前。
} # 函数结束
echo "global_var = $global_var" # global_var =
# 函数 "func" 还没被调用,
#+ 所以$global_var 在这里还不是可见的.
func
echo "global_var = $global_var" # global_var = 37
# 已经在函数调用的时候设置。
local声明变量的过程:
#!/bin/bash
echo "==OUTSIDE Function (global)=="
t=$(exit 1)
echo $? # 1
# 如预期一样.
echo
function0 ()
{
echo "==INSIDE Function=="
echo "Global"
t0=$(exit 1)
echo $? # 1
# 如预期一样.
echo
echo "Local declared & assigned in same command."
local t1=$(exit 1)
echo $? # 0
# local t1=$(exit 1),等价于:t1=$(exit 1) local t1; local t1执行成功所以$?为0
echo
echo "Local declared, then assigned (separate commands)."
local t2
t2=$(exit 1)
echo $?
}
function0
函数返回值
函数返回一个值,被称为退出状态码。这和一条命令返回的退出状态码类似。退出状态码可以由return 命令明确指定,也可以由函数中最后一条命令的退出状态码来指定(如果成功,则返回0,否则返回非0值)。可以在脚本中使用$?来引用退出状态码。 因为有了这种机制,所以脚本函数也可以像C函数一样有“返回值”。函数的返回值只能是0-255之间的整数,包含0和255。
来看一个函数的例子,取两个数中的最大值:
#!/bin/bash
# max.sh: 取两个Maximum of two integers.
E_PARAM_ERR=250 # 如果传给函数的参数少于两个时,就返回这个值。
EQUAL=251 # 如果两个参数相等时,就返回这个值。
# 任意超出范围的
#+ 参数值都可能传递到函数中。
max2 () # 返回两个数中的最大值。
{ # 注意:参与比较的数必须小于250.
if [ -z "$2" ]
then
return $E_PARAM_ERR
fi
if [ "$1" -eq "$2" ]
then
return $EQUAL
else
if [ "$1" -gt "$2" ]
then
return $1
else
return $2
fi
fi
}
echo -n "Please input first number:"
read first
echo -n "Please input second number:"
read second
max2 $first $second
return_val=$?
if [ "$return_val" -eq $E_PARAM_ERR ]
then
echo "Need to pass two parameters to the function."
elif [ "$return_val" -eq $EQUAL ]
then
echo "The two numbers are equal."
else
echo "The larger of the two numbers is $return_val."
fi
exit 0
函数示例
示例1: