-- 作者 谢恩铭 转载请注明出处

内容简介


  1. 前言
  2. 函数的作用
  3. 函数的定义
  4. 传递参数
  5. 返回值
  6. 变量作用范围
  7. 重载命令
  8. 函数的设计
  9. 总结
  10. 第五部分第七课预告

1. 前言


上一课 Linux探索之旅 | 第五部分第五课:循环往复,Shell开路 中我们学习了 Shell 中的循环语句。

这一课我们来学习对于大多数编程语言来说很重要的内容:函数。

2. 函数的作用


函数到底是什么呢?

以前在学校里学习数学的时候,也学过函数。例如:

y = 2x + 1复制代码

这个公式也被称为一个函数,对于每一个给定的 x 值,都会有一个 y 值被计算出来,就是 2 倍的 x ,加上 1。

因为编程的基础是数学,因此程序中的函数也有点数学中函数的原理,给它一定输入,它会为你产出一定的东西。

函数在英语中是 function,表示 「功能,作用」的意思。因此,你可以这么理解:函数是实现一定功能的代码块。

我们可以把函数比作一个香肠制造机,在输入那一头你把猪装进去,输出那一头就出来香肠了。

函数就像香肠制造机

函数还是重用代码(reuse code)的很好方式。

为什么这么说呢?

因为到目前为止,我们写的所有 Shell 文件,都是定义一些变量,然后执行一些命令,这些命令还都是逐行依次执行。

目前我们写的例子程序都比较短小,因此看不出有什么问题。假如这个文件的内容一多,达到好几万行甚至更多,而且有不少重复的内容,那么要维护这样一个庞杂的文件就极为困难。

这时候,函数就可以出马帮我们解围。因为函数可以把一块代码包裹起来,使之成为一个整体,完成某些任务。而且,我们在程序的其他地方,还可以多次使用这块代码。

这样,我们的程序就会变得有条理,也没有那么多重复的相似代码。你可以把函数想象成 Shell 脚本里的小脚本。

3. 函数的定义


说了这么多,也许还是不太好理解,我们不如实际来使用一下函数。

如果你学过其他编程语言,比如 C语言,Java,等等,那么其实 Shell 中的函数机理是与之类似的。但是,Shell 比较「任性」,它的函数形式和主流编程语言有不少区别。

定义(或创建) Shell 函数是非常容易的。有两种方式:

函数名 () {函数体
}复制代码

function 函数名 {函数体
}复制代码
  • 这两种方式都是可行的。看你个人喜好用哪一种方式。我个人喜欢第一种方式,因为 () 比 function 少好多个字符。要知道,程序员是要懂得偷懒的,少输入一点就节省时间(小编你真的为自己的懒惰找了很高大上的理由呢...)。

  • 函数名后面跟着的圆括号里不加任何参数:这一点与主流编程语言很不相同。C语言,Java,C++等语言中,函数的圆括号中是可以放置参数的(也就是函数的一部分输入),但是 Shell 中的函数的圆括号里不能放置参数。

  • 函数的完整定义必须置于函数的调用之前。

我们通过一个小例子来加深理解:

首先,用 vim 或其他文本编辑器来创建一个文件,叫作 function.sh。

vim function.sh复制代码

然后在里面输入以下内容:

#!/bin/bashprint_something () {echo Hello I am a function
}print_something
print_something复制代码

「 Hello I am a function 」是英语「 你好,我是一个函数」的意思。

运行:

可以看到程序打印了两次「 Hello I am a function 」。

我们逐行来解释这个程序:

  • 第 3 行 : 我们开始了一个函数的定义,给它起了一个名字,叫做 print_something (print 是英语 「打印」的意思,something 是英语 「某些东西」的意思)。
  • 第 4 行:在大括号 {} 中,我们可以写入多个命令。
  • 第 7 和 8 行:在函数定义之后,我们就可以调用它任意多次。这里连续调用了两次。

4. 传递参数


我们上面的函数并没有处理参数,有时候我们希望函数能为我们处理一些参数,然后输出一些结果。

在 Shell 函数中,我们给它传递参数的方式其实很像给 Shell 脚本传递命令行参数。我们把参数直接置于函数名字后面,然后就像我们之前 Shell 脚本的参数那样:$1, $2, $3, 等等。

我们来看一个例子:

#!/bin/bashprint_something () {echo Hello $1
}print_something Luke
print_something John复制代码

5. 返回值


大多数主流编程语言都有函数返回值的概念,可以让函数回传一些数据。

Shell 的函数却没办法做到。但是 Shell 的函数可以返回一个状态,有点类似一个程序或命令退出时会有一个退出状态,表明是否成功。

Shell 函数要返回状态,也用 return 这个关键字( return 是英语 「返回」的意思)。

来看一个例子:

#!/bin/bashprint_something () {echo Hello $1return 1
}print_something Luke
print_something John
echo Return value of previous function is $?复制代码
  • 第 5 行:返回的状态不一定要是被硬编码的(比如上例中的 1 ),也可以是一个变量。
  • 第 10 行:变量 $? 包含前一次被运行的命令或函数的返回状态。

运行:

一般来说,返回状态 0 表示一切顺利;一个非零值表示有错误。

如果你实在想要函数返回一个数值(比如说一个计算的值),那么你也可以用命令的执行结果。

如下:

#!/bin/bashlines_in_file () {cat $1 | wc -l
}line_num=$(lines_in_file $1)echo The file $1 has $line_num lines复制代码

运行:

6. 变量作用范围


变量的作用范围意味着一个 Shell 脚本的哪些部分可以访问到这个变量。

默认来说,一个变量是全局的(global),意味着在脚本的任何地方都可以访问它。

我们也可以创建局部(local)变量。当我们在函数中创建局部变量时,这个变量就只能在这个函数中被访问。

要定义一个局部变量,我们只要在第一次给这个变量赋值时在变量名前加上关键字 local 即可( local 是英语「 本地的」的意思)。

定义局部变量有一个好处,就是可以防止被脚本的其他地方的代码意外改变数值。

来看一个例子:

#!/bin/bashlocal_global () {local var1='local 1'echo Inside function: var1 is $var1 : var2 is $var2var1='changed again'var2='2 changed again'
}var1='global 1'
var2='global 2'echo Before function call: var1 is $var1 : var2 is $var2local_globalecho After function call: var1 is $var1 : var2 is $var2复制代码

运行:

在函数中,尽量用局部变量。只有实在不行才用全局变量,毕竟全局变量不太安全。

7. 重载命令


我们可以用函数来实现命令的重载,也就是说把函数的名字取成与我们通常在命令行用的命令相同的名字。

例如,也许我们每次在脚本中调用 ls 命令时,其实是想要实现 ls -lh 的效果。那么我们可以这么做:

#!/bin/bashls () {command ls -lh
}ls复制代码

第 4 行如果没有 command 这个关键字(command 是英语 「命令」的意思),那么程序会陷入无限循环。
如果你不小心忘了 command 关键字而陷入无限循环,可以用 Ctrl + c 的组合快捷键来停止程序。

运行:

8. 函数的设计


我们已经看到:在 Shell 中定义函数是很简单的。但是要定义容易维护和易于扩展的函数却需要经验和时间。

有时候,好的设计意味着更少的代码;有时候意味着需求变更时最少的改动;有时候意味着不容易引起错误。

如果一个任务需要被执行多次,那么把它放到一个函数里是不错的选择。

设计模式中有一个原则是 单一职责原则 ( Single Responsibility Principle )。这种原则也适用于函数的设计,尽量不要让一个函数执行很多个任务。

9. 总结


  1. 函数使我们可以轻松地重用代码,使程序更有条理,更易理解和扩展。

  2. 我们有两种定义函数的方式:「 function 函数名 」 或 「 函数名 () 」。

  3. 关键字 return 可以用于返回状态值。

  4. 关键字 local 可以用于定义局部变量。

  5. 关键字 command 使得函数可以重载命令。

10. 第五部分第七课预告


今天的课就到这里,一起加油吧!

下一课我们学习:Linux探索之旅 | 第五部分第七课:Shell实现图片展示网页


微信公众号「程序员联盟」ProgrammerLeague
我是谢恩铭,在巴黎奋斗的软件工程师。
我的简介
我的经历
热爱生活,喜欢游泳,略懂烹饪。
人生格言:“向着标杆直跑”

Linux 探索之旅 | 第五部分第六课:一朝 Shell 函数倾,斗转星移任我行相关推荐

  1. Linux 探索之旅 | 第五部分第八课:用 Shell 做统计练习

    -- 作者 谢恩铭 转载请注明出处 <Linux探索之旅>全系列 内容简介 前言 成果展示 解题步骤和答案 可能的优化 第五部分第九课预告 1. 前言 上一课 Linux探索之旅 | 第五 ...

  2. Linux 探索之旅 | 第五部分第五课:循环往复,Shell 开路

    -- 作者 谢恩铭 转载请注明出处 内容简介 前言 while 循环 until 循环 for 循环 总结 第五部分第六课预告 1. 前言 上一课 Linux探索之旅 | 第五部分第四课:条件一出,S ...

  3. Linux 探索之旅 | 第三部分第四课:后台运行及合并多个终端

    -- 作者 谢恩铭 转载请注明出处 内容简介 第三部分第四课:后台运行及合并多个终端 第三部分第五课预告:延时执行,唯慢不破 后台运行及合并多个终端 上一课 Linux探索之旅 | 第三部分第三课:监 ...

  4. 【C++探索之旅】第一部分第六课:控制流程,随心所至

    内容简介 1.第一部分第六课:控制流程,随心所至 2.第一部分第七课预告:函数效应,分而治之 控制流程,随心所至 上一课<[C++探索之旅]第一部分第五课:简易计算器>比较简单,这一课也不 ...

  5. 【Linux探索之旅】第二部分第三课:文件和文件夹,组织不会亏待你

    内容简单介绍 1.第二部分第三课:文件和文件夹,组织不会亏待你 2.第二部分第四课预告:文件操纵.鼓掌之中 文件和文件夹,组织不会亏待你 上一次课我们讲了命令行,这将成为伴随我们接下来整个Linux课 ...

  6. 【Linux探索之旅】第一部分第四课:磁盘分区,并完毕Ubuntu安装

    内容简单介绍 1.第一部分第四课:磁盘分区,并完毕Ubuntu安装 2.第一部分第五课预告:Unity桌面,人生若仅仅如初见 磁盘分区 上一课我们正式開始安装Ubuntu了.可是到了分区的那一步.小编 ...

  7. 【C语言探索之旅】 第一部分第六课:条件表达式

    内容简介 1.课程大纲 2.第一部分第六课:条件表达式 3.第一部分第七课预告:循环语句 课程大纲 我们的课程分为四大部分,每一个部分结束后都会有练习题,并会公布答案.还会带大家用C语言编写三个游戏. ...

  8. 【Linux探索之旅】第二部分第五课:用户和权限,有权就任性

    内容简单介绍 1.第二部分第五课:用户和权限,有权就任性 2.第二部分第六课预告:Nano,刚開始学习的人的文本编辑器 用户和权限.有权就任性 今天的标题也挺任性的啊,虽说小编是一个非常本分的人(真的 ...

  9. Linux 探索之旅 | 第三部分第五课:延时执行,唯慢不破

    -- 作者 谢恩铭 转载请注明出处 内容简介 第三部分第五课:延时执行,唯慢不破 第三部分第六课预告:第三部分测验题 延时执行,唯慢不破 上一课 Linux探索之旅 | 第三部分第四课:后台运行及合并 ...

最新文章

  1. 8500WN流畅高速上网高端卡 12核心不锁倍频
  2. 转:java中数组与List相互转换的方法
  3. 基于简单工厂模式的计算器程序
  4. 使用nsenter进入docker容器后端报错 mesg: ttyname failed: No such file or directory
  5. mybatis-plus 会自动增加 order by_python自动撸支付宝基金答题红包
  6. 人生的意义,呵!我找到了
  7. 自然数的拆分(信息学奥赛一本通-T1318)
  8. 富豪被劫,二十年一遇
  9. virtual memory exhausted: Cannot allocate memory Linux虚拟内存不足,扩展虚拟内存的解决办法
  10. session原理总结
  11. android简单小项目实例_300行C代码打造简单的闹钟小程序,适合初学C++同学练手的项目...
  12. 灰色预测理论matlab,利用灰色理论数据预测及MATLAB代码(数学建模).pdf
  13. 计算机星期六星期天的那个函数,WPS表格日期与时间函数
  14. 按键精灵手机助手学习笔记
  15. C语言运算优先级口诀
  16. 1、节假日万年历API接口,免费好用
  17. 百度、腾讯和阿里内部的级别和薪资待遇是什么样的?
  18. 如何让自己的博客被搜索引擎收录
  19. Python学习笔记(十五):python 中的面向对象
  20. 微信第三方登录有两种登录方式, 1. 微信开放平台登录 2. 微信公众平台授权登录?

热门文章

  1. LeetCode 46. Permutations
  2. mysql数据库中 pri_MySQL数据库管理——SQL指令集
  3. mysql期中考试题及答案_MySQL数据库考试试题与答案
  4. asset文件夹路径 unity_Unity Assets目录下的特殊文件夹名称
  5. 怎么看so文件是哪个aar引进来的_运城人才引进7月5号面试
  6. Tuxedo FAQs 整理
  7. Perl_获得字符串长度_length($var)
  8. java 权限管理与用户角色权限设计
  9. SpringCloud微服务实战(一)-简介
  10. CSS学习总结3:CSS定位