Linux 命令行与 shell 脚本编程大全 17 创建函数

介绍如何在 shell 脚本中创建函数,以及如何在 shell 脚本中使用这些函数

更多精彩

导览

  1. 为了提高脚本中代码的重用性,可以将指定代码块封装为一个函数,然后在脚本中通过函数的名称对函数进行调用
  2. 脚本函数可以用函数最后一条命令的退出状态码或 return 命令来返回指定数值,范围在 0-255 之间
  3. 函数也可以使用 echo 语句输出返回值,这可以让函数的返回值不局限于数值
  4. 可以再函数中使用 shell 变量,函数的变量分为 全局变量局部变量局部变量 需要添加 local 前缀
  5. 函数可以调用包裹其自身在内的其他函数,函数调用自身的方式叫做 递归
    • 在使用递归时必须设置一个终结条件,否则会导致无限循环
  6. 使用 函数库文件 可以实现函数在不同脚本中的调用,只需要在调用的脚本中使用 source 命令引入指定 函数库文件 即可
  7. 可以直接在命令行创建和调用函数,也可以将函数写在 .bashrc ,实现函数的全局调用
  8. 函数库文件.bashrc 中进行 source 命令的调用,也可以实现函数的全局调用

17.1 基本的脚本函数

  1. 函数是一个脚本代码块,可以为其指定一个名称并在脚本中进行调用

17.1.1 创建函数

  1. 脚本中每个函数的名称都不能重复

17.1.1.1 基本语法

function name {
  commands
}

17.1.1.2 简写语法

name() {
  commands
}

17.1.2 使用函数

  1. 在脚本中创建函数后,就可以在后续代码中进行调用,如下图
  2. 需要注意的是,函数并不是必须得在脚本的开始位置进行创建 ,但是 函数必须在其被调用之前创建
  3. 如果函数的创建语句在其调用语句之后,shell 会因为找不到被调用的函数而抛出异常


17.1.2.1 函数名称的唯一性

  1. 如果在脚本中定义了重名的函数,那么新定义的函数会覆盖之前的函数,如下图


17.2 返回值

17.2.1 默认退出状态码

  1. 11.8.1 查看退出状态码 中已经介绍过退出状态码的概念,常见的退出状态码可以参考下图
  2. 默认情况下, 函数的退出状态码时函数中最后一条命令返回的退出状态码
  3. 在函数执行完毕后,可以立即用标准变量 $? 来确定函数的退出状态码,如下图
    • 可以看到,在 exitCode 函数的最后使用 ls badDir 查询了一个不存在的目录
    • 那么该命令的退出状态码肯定是 1 ,使用 $? 可以正常获取到该值
  4. 但是如果有异常的命令不是最后一条命令,则无法得知该命令的执行结果,如下图
    • 相对于上一个脚本,该脚本只是将函数内部的两个命令互换了位置
    • 但是得到的函数返回值却截然相反,所以这种直接通过 $? 获取函数返回值的方式,没有多少实用意义

17.2.2 使用 return 命令

  1. 使用 return 命令可以退出函数,并返回特定的退出状态码
  2. return 命令允许指定一个整数值来自定义函数的退出状态码,如下图

17.2.2.1 使用退出状态码作为函数返回值的缺陷

  1. 要获取退出状态码需要使用 $? ,而且需要在函数执行之后立即使用,如果在其中穿插了其他命令,就无法获取到函数最后一条命令的退出状态码
  2. 退出状态码的取值范围是 0-255 ,不在这个范围内的值无法作为退出状态码来赋予函数返回值

17.2.3 使用函数输出

  1. 函数可以将 echo 的输出内容作为函数的返回值,如下图
    • 函数中的 echo 语句虽然输出了一句话,但函数被调用后,这句话并没有立即输出
    • 它作为函数的返回值被保存到了 result 变量中,直到该变量被 echo 使用时,函数的返回值才被输出
    • 而且可以看到,使用这种方式时,函数的返回值不局限于数字


17.3 在函数中使用变量

17.3.1 向函数传递参数

  1. 可以使用给脚本传参的方式给函数传参,函数内部对于传入参数的调用方式也和脚本中调用保持一致,如下图


17.3.2 在函数中处理变量

  1. 在函数中可以使用 全局变量 ,以及 局部变量
    • 函数中定义的 局部变量 对于函数以外的部分,是不可见的

17.3.2.1 全局变量

  1. 默认情况下,在脚本中定义的任何变量都是全局变量

17.3.2.2 局部变量

  1. 使用 local 关键字声明的变量就是局部变量,该变量只能在其声明的函数内部才能访问,如下图
    • 两个 result 变量,虽然名称相同,但由于函数内部的是局部变量,所以互不影响

17.4 数组变量和函数

17.4.1 向函数传递数组参数

  1. 如果试图直接将数组作为参数传递到函数中,将无法得到完整的数组内容,只能得到数组的第一个值,如下图
    • 正常的使用 ${array[*]} 可以获取到数组的全部内容
    • 但是将数组作为一般参数传入到函数中后,不论如何操作,都只能获取到数组的第一个值,所以数组不能作为一般参数直接传入函数


17.4.1.1 将数组内容分解后传入函数

  1. 想要让函数能够获取到完整的数组内容,需要先将数据的内容分解成为普通的参数列表
  2. 然后在函数中对传入的所有参数进行重新组装,获取一个新的数组,如下图
    • 将数组传入函数时使用的 arrayParam ${array[*]} ,其实就是将数组的输出结果 1 2 3 作为普通参数全部传给函数
      • 完整形式就是 arrayParam 1 2 3
    • 然后在函数内容使用 ($(echo "$@")) 将参数一次性输出,并包装成为数组内容

17.4.2 从函数返回数组

  1. 其实和将数组作为普通参数传入到函数中一样
  2. 想要从函数内部返回数组,只需要将函数内部的数组作为普通参数输出即可,如下图


17.5 函数递归

  1. 递归其实就是函数自己调用自己,但必须为递归准备一个最终条件,否则会导致无限循环
  2. 递归算法的经典例子是计算阶乘,例如 5! = 1 * 2 * 3 * 4 * 5 = 120 ,公式是 x! = (x * (x -1))!
  3. 用脚本来表示的话,如下图


17.6 创建库

  1. 利用 函数库文件 可以实现一个函数在不同的脚本中被重复调用
  2. 使用 source 命令可以在指定脚本中调用 函数库文件
    • 默认情况下,由于 shell 函数作用域的限制,函数只会在其被定义的脚本中生效
    • 但是 source 命令会在当前 shell 上下文中执行命令,而不是创建一个新 shell ,相当于把目标脚本解析到了当前脚本中
  3. source 命令的语法分两种
    • 完整语法 source ./file
    • 简写语法 . ./file
  4. 写一个简单例子演示一下,如下图


17.7 在命令行上使用函数

17.7.1 在命令行上创建函数

  1. 使用这种方式创建的函数都是临时的,一旦当前 shell 退出,这些被创建的函数都将不复存在
  2. 而且这种方式不但没有什么实际意义,还非常危险,如果误将函数的名称和当前系统中其他命令的名称重名了,那么这个系统命令将会被覆盖

17.7.1.1 单行定义函数

  1. 其实就是将一个简单的的函数直接在命令行上进行创建,如下图
    • 在每个命令的最后都需要添加分号,这样 shell 才会知道命令的开始和结束在什么时候发生


17.7.1.2 多行定义函数

  1. 使用 shell 的 次提示符( > ) 来输入更多命令,如下图
    • 当输入 { 后按下回车,会直接进入函数的多行模式
    • 当输入 } 后按下回车,会直接退出函数的多行模式

17.7.2 在 .bashrc 文件中定义函数

  1. 因为 .bashrc 文件是的特性,用户在开启每个 shell 进程时,系统都会扫描该文件
  2. 所以可以把该文件作为一个默认的 全局函数库文件 ,将函数直接写在这个文件中,将可以直接实现函数的全局调用
  3. 但该文件中也会存在一些系统预置的内容,所以直接添加各种自定义函数,容易导致文件内容变的混乱
  4. 所以也可以使用 source 命令将一些自定义的 函数库文件 ,在该文件的末尾进行引用

17.8 实例

  1. 介绍 GNU shtool shell 脚本函数库如何安装和使用,跳过了
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 160,999评论 4 368
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 68,102评论 1 302
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 110,709评论 0 250
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 44,439评论 0 217
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,846评论 3 294
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,881评论 1 224
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 32,062评论 2 317
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,783评论 0 205
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,517评论 1 248
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,762评论 2 253
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,241评论 1 264
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,568评论 3 260
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,236评论 3 241
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,145评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,941评论 0 201
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,965评论 2 283
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,802评论 2 275

推荐阅读更多精彩内容