| 函数就是用来盛放一组代码的容器,函数内的一组代码完成一个特定的功能,称之为一组代码块,调用函数便可触发函数内代码块的运行,这可以实现代码的复用,所以函数又可以称之为一个工具 |
| 具备某一功能的工具=>函数 |
| 事先准备好哦工具=>函数的定义 |
| 遇到应用场景,拿来就用=>函数的调用 |
| |
| 所以函数的使用原则:先定义,后调用 |
| |
| [ function ] funname [()] |
| { |
| 命令1; |
| 命令2; |
| 命令3; |
| ... |
| [return int;] |
| } |
| |
| |
| function 函数名() { |
| 函数要实现的功能代码 |
| } |
| |
| |
| function 函数名 { |
| 函数要实现的功能代码 |
| } |
| |
| |
| 函数名() { |
| 函数要实现的功能代码 |
| } |
| |
| 函数名 |
| 函数名 参数1 参数2 |
| |
| |
| function test1(){ |
| echo "执行第一个函数" |
| } |
| |
| function test2 { |
| echo "执行第二个函数" |
| } |
| |
| test3(){ |
| echo "执行第三个函数" |
| } |
| |
| |
| test1 |
| test2 |
| test3 |
| |
| |
如果把函数当成一座工厂,函数的参数就是为工厂运送的原材料
-
调用函数时可以向其传递参数
| |
| test1 111 222 333 444 555 |
-
在函数体内部,通过 $n
的形式来获取参数的值,例如,$1
表示第一个参数,$2
表示第二个参数…当n>=10时,需要使用${n}
来获取参数
| [root@egon ~] |
| function test1(){ |
| echo "...start..." |
| echo $1 |
| echo $2 |
| echo $3 |
| echo "...end..." |
| } |
| |
| test1 111 222 333 444 555 |
| |
| [root@egon ~] |
| ...start... |
| 111 |
| 222 |
| 333 |
| ...end... |
ps:在脚本内获取脚本调用者在命令行里为脚本传入的参数,同样使用的是$n,不要搞混
| [root@egon ~] |
| function test1(){ |
| echo "...start..." |
| echo "这是函数内:$1" |
| echo "这是函数内:$2" |
| echo "这是函数内:$3" |
| echo "...end..." |
| } |
| |
| |
| test1 |
| |
| echo "这是脚本级的参数$1" |
| echo "这是脚本级的参数$2" |
| echo "这是脚本级的参数$3" |
| |
| [root@egon ~] |
| [root@egon ~] |
| [root@egon ~] |
| ...start... |
| 这是函数内: |
| 这是函数内: |
| 这是函数内: |
| ...end... |
| 这是脚本级的参数xxx |
| 这是脚本级的参数yyy |
| 这是脚本级的参数zzz |
| [root@egon ~] |
温故知新
参数处理 |
说明 |
$# |
传递到脚本或函数的参数个数 |
$* |
所有参数 |
$@ |
所有参数,与$*类似 |
$$ |
当前脚本进程的ID号 |
$? |
获取上一条命令执行完毕后的退出状态。0表示正确,非0代表错误,如果执行的是函数那么$?取的是函数体内return后的值 |
ps:
示例
| [root@egon ~] |
| echo "=======函数test1===========" |
| function test1(){ |
| echo "$*" |
| echo "$@" |
| echo $ |
| echo $$ |
| echo $? |
| } |
| |
| test1 111 222 333 444 555 |
| |
| echo "=======函数test2===========" |
| function test2(){ |
| for i in "$*" |
| do |
| echo $i |
| done |
| } |
| |
| test2 111 222 333 "444 555" |
| |
| |
| echo "=======函数test3===========" |
| function test3(){ |
| for i in "$@" |
| do |
| echo $i |
| done |
| } |
| |
| test3 111 222 333 "444 555" |
| |
| |
| |
| |
| |
如果把函数当成一座工厂,函数的返回值就是工厂的产品,在函数内使用return关键字返回值,函数内可以有多个return,但只要执行一个,整个函数就会立刻结束
| [root@egon ~] |
| function test1(){ |
| echo 111 |
| return |
| echo 222 |
| return |
| echo 333 |
| } |
| |
| test1 |
| |
| [root@egon ~] |
| [root@egon ~] |
| 111 |
需要注意的是shell语言的函数中,通常用return返回函数运行是否成功的状态,0代表成功,非零代表失败,需要用$?获取函数的返回值
-
1、如果函数内没有return,那么将以最后一条命令运行结果(命令运行成功结果为0,否则为非0)作为返回值
| [root@egon ~] |
| function test1(){ |
| echo 111 |
| echo 222 |
| echo 333 |
| xxx |
| } |
| |
| test1 |
| echo $? |
| [root@egon ~] |
| 111 |
| 222 |
| 333 |
| ./b.sh:行5: xxx: 未找到命令 |
| 127 |
-
2、如果函数内有return,那么return后跟的只能是整型值并且范围为0-255,用于标识函数的运行结果是否正确, 与C 语言不同,shell 语言中 0 代表 true,0 以外的值代表 false
| [root@egon ~] |
| function test1(){ |
| echo 111 |
| echo 222 |
| echo 333 |
| return 0 |
| } |
| |
| test1 |
| echo $? |
| [root@egon ~] |
| 111 |
| 222 |
| 333 |
| 0 |
Shell 变量的作用域(Scope),就是 Shell 变量的有效范围(可以使用的范围)。
1、局部变量:只能在函数内访问
使用local关键字定义在函数内的变量属于局部范围,只能在函数内使用,如下所示
| [root@localhost shell] |
| |
| |
| |
| function test(){ |
| local x=111 |
| echo "函数内访问x:$x" |
| } |
| |
| |
| test |
| |
| echo "在函数外即全局访问x:$x" |
执行结果
| [root@localhost shell] |
| 函数内访问x:111 |
| 在函数外即全局访问x: |
2、全局变量:可以在当前shell进程中使用
所谓全局变量,就是指变量在当前的整个 Shell 进程中都有效。每个 Shell 进程都有自己的作用域,彼此之间互不影响。在 Shell 中定义的变量,默认就都是全局变量。
| [root@localhost shell] |
| |
| x=2222 |
| |
| function test(){ |
| echo "函数内访问x:$x" |
| } |
| test |
| echo "在函数外即全局访问x:$x" |
执行结果
| [root@localhost shell] |
| 函数内访问x:2222 |
| 在函数外即全局访问x:2222 |
请注意
-
1、在函数内定义的变量,如果没有用local声明,那么默认也是全局变量,shell变量语法的该特性与js的变量是类似的(在js函数内部定义的变量,默认也是全局变量,除非加上关键字var)
| [root@localhost shell] |
| |
| function test(){ |
| x=2222 |
| } |
| test |
| echo "在函数外即全局访问x:$x" |
| |
| [root@localhost shell] |
| 在函数外即全局访问x:2222 |
-
2、每执行一个解释器,都会开启一个解释的shell进程,每个shell进程都有自己的作用域彼此互不干扰
| [root@localhost shell] |
| [root@localhost shell] |
| 111 |
| [root@localhost shell] |
| [root@localhost shell] |
| |
| [root@localhost shell] |
-
3、需要强调的是:
全局变量的作用范围是当前的 Shell 进程,而不是当前的 Shell 脚本文件,它们是不同的概念。打开一个 Shell 窗口就创建了一个 Shell 进程,打开多个 Shell 窗口就创建了多个 Shell 进程,每个 Shell 进程都是独立的,拥有不同的进程 ID。在一个 Shell 进程中可以使用 source 命令执行多个 Shell 脚本文件,此时全局变量在这些脚本文件中都有效。
| [root@localhost shell] |
| |
| [root@localhost shell] |
| |
| function test(){ |
| x=2222 |
| } |
| test |
| |
| [root@localhost shell] |
| [root@localhost shell] |
| 2222 |
| [root@localhost shell] |
| [root@localhost shell] |
| [root@localhost shell] |
| |
| echo $x |
| |
| [root@localhost shell] |
| 2222 |
结论:函数test内的全局变量x早已超越了文件,即全局变量是超越文件的,作用范围是整个当前bash进程
3、环境变量:在当前进程的子进程中都可以使用
全局变量只在当前 Shell 进程中有效,对其它 Shell 进程和子进程都无效。如果使用export
命令将全局变量导出,那么它就在所有的子进程中也有效了,这称为“环境变量”。
环境变量被创建时所处的 Shell 进程称为父进程,如果在父进程中再创建一个新的进程来执行 Shell 命令,那么这个新的进程被称作 Shell 子进程。当 Shell 子进程产生时,它会继承父进程的环境变量为自己所用,所以说环境变量可从父进程传给子进程。不难理解,环境变量还可以传递给孙进程。
| [root@localhost shell] |
| [root@localhost shell] |
| [root@localhost shell] |
| 333 |
| [root@localhost shell] |
| [root@localhost shell] |
| 333 |
| |
| ps:通过exit命令可以一层一层地退出 Shell。 |
ps:命令set 和 env
注意
-
1、环境变量只能向下传递而不能向上传递,即“传子不传父”。
-
2、两个没有父子关系的 Shell 进程是不能传递环境变量的
| 我们一直强调的是环境变量在 Shell 子进程中有效,并没有说它在所有的 Shell 进程中都有效;如果你通过终端创建了一个新的 Shell 窗口,那它就不是当前 Shell 的子进程,环境变量对这个新的 Shell 进程仍然是无效的。 |
-
3、环境变量也是临时的
| [root@localhost ~] |
| root 123436 0.0 0.1 116356 2960 pts/0 Ss 21:52 0:00 -bash |
| root 123492 0.0 0.1 116472 2932 pts/0 S 21:54 0:00 bash |
| root 123520 0.0 0.1 116440 2988 pts/0 S 21:54 0:00 bash |
| |
| 注意: |
| |
| |
| 一旦退出了在终端登录的顶级shell,那么该终端下开启的所有子shell都会被回收,export设置的环境变量随即消失 |
所以说环境变量也是临时的,如果想设置成永久的,需要将变量写入shell配置文件中才可以,Shell 进程每次启动时都会执行配置文件中的代码做一些初始化工作,如果将变量放在配置文件中,那么每次启动进程都会定义这个变量。请看下一小节