Shell编程基础:函数

本博文目录索引

[TOC]


一、认识函数

(一)什么是函数?

1、函数,英文名叫:function
2、函数是由若干shell命令组成的语句块

(二)为什么要使用函数?

1、实现代码复用,节省大量重复的代码块
2、实现模块化编程,不同的功能模块之间相对独立,有利于Shell语句块的bug调试和功能更新

(三)函数与Shell脚本的关系

1、函数一般放在Shell脚本中,属于Shell脚本的一部分
2、函数不能独立运行,需要在Shell脚本中调用运行
3、Shell脚本运行时会创建一个Bash子进程,被调用的函数运行在这个子进程中

(四)关于函数理解的误区

1、函数不能单独运行,必须被调用运行
2、函数被调用运行时,无法开启子进程,只能运行在当前Bash进程中
3、函数被调用运行时,可以使用当前Bash进程的普通变量和全局变量,并且可以对它们进行重新赋值、或者取消赋值

二、定义函数

(一)函数的组成结构

函数由两部分组成:函数名和函数体

1、函数名

(1)函数的名字,通用写法是:func_name
(2)在Shell脚本中调用函数时需要用到函数名
(3)函数名的命名必须遵守命名规范!

2、函数体

(1)函数的主体,即由若干shell命令组成的语句块
(2)语句块使用一对花括号 { } 包含起来,语句块与花括号之间必须用空格隔开!

(二)函数名命名规范

1、建议的函数名命名标准:func_ + 驼峰法

  • 小驼峰:func_namingNotation
  • 大驼峰:func_NamingNotation

2、警告: 为了避免函数名与命令名冲突,不建议把内部命令名、外部命令名、命令别名当作函数名的命名!!!

(三)函数定义的语法格式

1、第一种语法格式

func_name(){
    ...函数体...
}

2、第二种语法格式

function func_name{
    ...函数体...
}

3、第三种语法格式

function func_name(){
    ...函数体...
}

三、函数使用

(一)函数的三种使用方式

1、可在交互式环境下定义函数
2、可将函数放在脚本文件中,作为脚本文件的一部分
3、可放在只包含函数的单独文件中

(二)交互式环境定义和使用函数

[root@Alvin ~]#  #在交互式环境下定义函数
[root@Alvin ~]#func_dir(){
[root@Alvin ~]> ls -l
[root@Alvin ~]> }
[root@Alvin ~]#  #在交互式环境下调用函数
[root@Alvin ~]#func_dir

1、在交互式环境下,可以通过输入 左花括号{ 触发多行重定向,在多行重定向中输入代码块,然后以 右花括号} 结束多行重定向的方式,定义func_dir函数
2、定义该函数之后,在交互式环境下,可以通过函数名func_dir调用运行此函数,执行效果相当于直接执行 ls -l
3、定义该函数之后,该函数会在当前Bash进程退出前一直保留
4、当前Bash进程退出时,该函数立即失效
5、也可以在当前Bash进程中运行 unset 命令,使该函数立即失效

[root@Alvin ~]#  #在交互式环境下取消函数
[root@Alvin ~]#unset func_dir

(三)在脚本中定义及使用函数

#!/bin/bash
#fileName:func_test.sh
#在脚本中定义函数
func_helloWorld(){
    echo "Hello World!";
    echo "Today is `date +%F`";
}
#在脚本中调用函数
func_helloWorld;

执行效果:在标准输出打印以下两行信息
Hello World!
Today is 2018-05-10

1、注意:函数必须 先定义、再调用!
2、函数定义代码块必须放在脚本开始部分,函数调用必须在函数定义代码块之后
3、调用函数时仅使用该函数名即可
4、该函数的有效期为此脚本创建的Bash子进程的生命期,该Bash子进程一旦结束退出,该函数立刻失效

(四)使用函数文件

1、为什么要使用函数文件?

(1)可以将经常使用的函数存入函数文件,然后通过函数文件载入Shell的方式,实现函数复用
(2)函数文件名建议与相关任务有某种联系

举例:用来获取本机eth0网卡的IPv4地址
functions.showIP

2、创建函数文件

#!/bin/bash
#fileName:functions.showIP
#在函数文件中定义函数
showIP(){
    #用来获取本机eth0网卡的IPv4地址,CentOS6和CentOS7通用!
    ip a | grep -A 2 "^2:"|tail -n 1 | sed -r 's/.* ([1-9].*)\/.*/\1/';
}

注意:函数文件名是functions.showIP,函数名是showIP

(1)函数文件的书写格式和Shell脚本的书写格式是一样的,但是函数文件中主要是存放函数定义
(2)函数文件一般是普通的文本文件,不带有可执行属性

3、将函数文件载入Shell进程

(1)在交互式环境下将函数文件载入当前Bash进程

[root@Alvin ~]#  #在交互式环境下将函数文件载入当前Bash进程
[root@Alvin ~]#source ./functions.showIP
[root@Alvin ~]#  #在交互式环境下调用函数文件中的函数showIP
[root@Alvin ~]#showIP

执行效果:在标准输出打印本机eth0网卡的IPv4地址
172.20.43.100

(2)在脚本中将函数文件载入当前脚本创建的Bash子进程

#!/bin/bash
#fileName:test_showIP.sh
#在脚本中将函数文件载入当前脚本创建的Bash子进程
source ./functions.showIP;
#在当前脚本创建的Bash子进程中调用函数文件中的函数showIP
showIP;

执行效果:在标准输出打印本机eth0网卡的IPv4地址
172.20.43.100

(3)载入函数文件的语法格式

第一种语法格式:
source /PATH/fileName
<source><空格><文件名>

第二种语法格式:
. /PATH/fileName
<点><空格><文件名>

(4)注意事项

这里的文件名要带正确的路径,可以使用绝对路径或相对路径

4、检查函数是否已载入当前Bash进程

[root@Alvin ~]#在交互式环境下查看当前Bash进程已经载入的所有函数
[root@Alvin ~]#set

执行效果:在标准输出打印当前Bash进程已经载入的所有函数
[此处省略输出信息]

5、删除已经载入当前Bash进程的函数

在对函数定义做过修改之后,需要先删除已经载入当前Bash进程,使其对当前Bash进程不可用

[root@Alvin ~]#  #删除已经载入当前Bash进程的函数showIP
[root@Alvin ~]#unset showIP

命令格式:
unset func_name

6、环境函数

(1)默认情况下定义的函数只在当前Bash进程有效,无法传递给当前Bash进程的子进程,这种函数叫做 普通函数
(2)可以借助export使得函数可以在当前Bash进程及其子进程有效,这种函数叫做 环境函数
(3)注意: 函数必须先定义,然后才能被export声明为环境函数!环境函数的定义和声明无法合并!!!

[root@Alvin ~]#  #声明环境函数
[root@Alvin ~]#export -f showIP

命令格式:
export -f func_name

[root@Alvin ~]#  #只查看当前Bash进程已经声明的环境函数
[root@Alvin ~]#export -f
[root@Alvin ~]#declare -xf

注意:
set 是查看当前Bash进程生效的所有函数
export -f 或者 declare -xf 只查看当前Bash进程已经声明的环境函数

四、函数成员

(一)函数参数

1、回顾:shell中常见的参数和特殊变量

参数名/特殊变量名 表达的含义
$1 第一个位置参数
$2 第二个位置参数
$@ 位置参数列表当成一个整体
$* 位置参数列表成员彼此独立
$# 位置参数的个数

2、传递参数给函数

调用函数时,在函数名后面以空白分割给定参数列表即可

#!/bin/bash
#fileName:test_argsList4Func.sh
#在脚本中定义函数
func_argsList4Func(){
    #获取位置参数列表
    echo $#;
}
#在脚本中调用函数
func_argsList4Func;
[root@Alvin ~]#  #把参数列表传递给脚本中的函数
[root@Alvin ~]#bash ./test_argsList4Func.sh a b c;

执行效果:在标准输出打印位置参数的个数
3

(二)函数变量

1、函数内部的三种变量

(1)普通变量
(2)环境变量
(3)本地变量

2、普通变量

(1)在函数体中以默认形式定义的变量,都是普通变量
(2)普通变量的作用范围 仅当前Shell进程有效
(3)当当前Shell进程结束退出时,普通变量会被自动销毁

3、环境变量

(1)在函数体中使用 export 声明的变量,就是环境变量
命令格式:
export NAME=VALUE

(2)环境变量的作用范围是 当前Shell进程及其Shell子进程
(3)只有当当前Shell进程及其Shell子进程全部结束退出时,环境变量才会被销毁

4、本地变量

(1)在函数体中使用 local 声明的变量,就是本地变量
命令格式:
local NAME=VALUE

(2)本地变量 仅在所在函数体中有效,无法越过函数体影响当前Shell进程
(3)当函数调用结束时,本地变量会自动被销毁

(三)函数返回值

1、函数的两种返回值

(1)函数的执行结果返回值
(2)函数的退出状态码

2、函数的执行结果返回值

(1)函数体内部使用echo等命令,执行结果当作返回值输出

#!/bin/bash
#fileName:test_echoReturnValue.sh
#在脚本中定义普通函数
func_echoReturnValue(){
    #使用echo命令
    echo Hello World!;
}
#在脚本中调用普通函数
func_echoReturnValue;
[root@Alvin ~]#  #在当前Bash进程的Bash子进程中运行脚本
[root@Alvin ~]#bash ./test_echoReturnValue.sh

执行效果:在标准输出打印一行信息
Hello World!

(2)函数体内部调用命令,执行结果当作返回值输出

#!/bin/bash
#fileName:test_showIPReturnValue.sh
#在脚本中定义普通函数
func_showIPReturnValue(){
    #调用ip命令
    ip a | grep -A 2 "^2:"|tail -n 1 | sed -r 's/.* ([1-9].*)\/.*/\1/';
}
#在脚本中调用普通函数
func_showIPReturnValue;
[root@Alvin ~]#  #在当前Bash进程的Bash子进程中运行脚本
[root@Alvin ~]#bash ./test_showIPReturnValue.sh

执行效果:在标准输出打印本机eth0网卡的IPv4地址
172.20.43.100

3、函数的退出状态码

(1)默认取决于函数中执行的最后一条命令的退出状态码

#!/bin/bash
#fileName:test_defaultReturnValue.sh
#在脚本中定义普通函数
func_defaultReturnValue(){
    #调用true命令,没有任何标准输出,只有退出状态码为0
    true;
}
#在脚本中调用普通函数
func_defaultReturnValue;
#查看函数中执行的最后一条命令的退出状态码
echo $?;
[root@Alvin ~]#  #开启Bash子进程运行包含函数调用的脚本
[root@Alvin ~]#bash ./test_defaultReturnValue.sh

执行效果:在标准输出打印一行信息
0

(2)自定义退出状态码

#!/bin/bash
#fileName:test_assignReturnValue.sh
#在脚本中定义普通函数
func_assignReturnValue(){
    #指定退出状态码为255
    return 255;
}
#在脚本中调用普通函数
func_assignReturnValue;
#查看函数中的自定义退出状态码
echo $?;
[root@Alvin ~]#  #开启Bash子进程运行包含函数调用的脚本
[root@Alvin ~]#bash ./test_assignReturnValue.sh

执行效果:在标准输出打印一行信息
255

-EOF-

猜你喜欢

转载自www.cnblogs.com/Gym-UMan-Alvin/p/9026823.html
今日推荐