首页 Shell 函数
文章
取消

Shell 函数

定义与使用

在 shell 中,同样有函数的概念,具体语法如下:

其中,function()return都可以省略。

如果没有return语句,那么默认返回最后一条命令的退出值;

如果有return语句,那么返回值类型为 int([0, 255])。

1
2
3
4
5
6
7
function func_name() {
    command1
    command2
    ...
    commandN
    return exit_code
}

定义好函数之后,我们就可以使用它了(允许在函数中定义函数,和变量一样);

使用函数很简单,一个函数就和一个普通的命令一样,只需要写函数名,不用加()

如:func_name;还可以传递参数,func_name arg1 arg2 arg3,在函数内部使用$n获取;

其中$0为当前可执行文件名,$1为第一个参数、$2为第二个参数,…,以此类推;

使用$#获取参数个数,$@$*获取所有传递的参数,$?可在函数外部获取函数返回值。

$@$*的区别前面说过,这里不再叙述,你会发现函数和一个 shell 脚本在用法上很相似。

递归调用

在 shell 函数中,同样支持递归调用,即自己调用自己。

并且,我发现 bash 中没有深度限制,可以一直递归下去;但是在 zsh 中就有 1000 层限制。

关于 bash 函数,还有几点要说明一下:

  • 必须先定义函数,才能使用,不支持类似 C/C++ 中的函数声明;
  • 在一个函数中,可以调用另一个已定义的函数,也可以调用本身。

函数局部变量

在函数中,我们可以访问全局变量(读取、修改);也可以定义新的变量;

但是要注意,在函数中定义的变量默认是全局变量,即在函数外部依旧可以访问;

那么,如何定义函数局部变量呢?使用关键字local,如local var_name=value

这时,var_name变量就是一个局部变量,在函数外部不可访问,只能在函数内部使用。

如果局部变量和全局变量有命名冲突(变量名一样),则优先使用局部变量(优先级高)。

具名函数、匿名函数

  • 具名函数:通常情况下我们定义的都是具名函数,也就是都有函数名;
  • 匿名函数:使用{ command1; command2; ...; commandN; }来定义和使用匿名函数。

匿名函数不能有 return,如果花括号与命令在同一行,要空格隔开(左括号)和分号结束(右括号);

{ echo www.zfl9.com; };如果不在同一行,就不需要使用空格隔开和分号结束,具体例子:

1
2
3
4
5
6
7
8
9
10
11
12
#!/bin/bash

# 正确
{ echo www.zfl9.com;}

# 正确
{ echo www.zfl9.com; }

# 正确
{
    echo www.zfl9.com
}

函数定义的推荐语法

使用标准的、可移植的 func_name() { ... } 形式。

此外,再介绍一个特殊的语法:func_name() ( ... ),看例子:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
#!/bin/bash

func1() {
    echo "[func1] change dir to /etc"
    cd /etc
    echo "[func1] current dir is: $(pwd)"
}

func2() (
    echo "[func2] change dir to /bin"
    cd /bin
    echo "[func2] current dir is: $(pwd)"
)

cd /

echo "[main] before call func1: $(pwd)"
func1
echo "[main] after call func1: $(pwd)"

echo "[main] before call func2: $(pwd)"
func2
echo "[main] after call func2: $(pwd)"
1
2
3
4
5
6
7
8
9
10
11
$ chmod +x test.sh

$ ./test.sh
[main] before call func1: /
[func1] change dir to /etc
[func1] current dir is: /etc
[main] after call func1: /etc
[main] before call func2: /etc
[func2] change dir to /bin
[func2] current dir is: /bin
[main] after call func2: /etc

func_name() { ... } 定义的是一个具名函数,shell 中的函数都是在当前 shell 进程中执行的,所以使用 cd 改变工作目录时会影响到当前 shell 进程;

func_name() ( ... ) 定义的是一个具名子程序,当你调用这个“函数”时,其实相当于调用一个外部的 shell script 脚本,该子程序运行在独立的 shell 进程,该 shell 进程与调用者所在的 shell 进程是互不影响的。在某些场合, 使用 func_name() ( ... ) 有奇效。

本文由作者按照 CC BY 4.0 进行授权

Shell IFS 变量

Shell 重定向