天天看点

SHELL脚本编程进阶(二)第一部分 函数第二部分 数组

本文部分资料和示例援引自以下书籍。在此,感谢原作者的创作,以及所有译者的付出,向他们致敬。

<a href="http://www.tldp.org/LDP/abs/html/" target="_blank">Advanced Bash-Scripting Guide</a>

<a href="https://linuxstory.gitbooks.io/advanced-bash-scripting-guide-in-chinese/content/" target="_blank">《高级Bash脚本编程指南》Revision 10中文版</a>

<a href="https://bash.cyberciti.biz/guide/Main_Page" target="_blank">Linux脚本编程执导</a>

第一部分 函数 1. 函数定义 2. 函数使用 3. 函数返回值 4. 函数参数 5. 函数变量 6. 函数的递归调用 第二部分 数组 1. 数组声明与赋值 2. 数组引用 3. 数组的数据处理
函数,任何一门高级编程语言中都具备的一种代码结构。其实是借用了工程上模块化的思想。函数的作用能够将简化代码的编写,使得程序结构更加的清晰。同时函数能够复用重复的代码,实现代码重用和模块化。  bash中函数是由若干条shell命令组成的语句块,与shell程序形式上是相似的,不同的是它不是一个单独的进程,不能独立运行,而是shell程序的一部分。  函数由两部分组成:函数名和函数体 ,bash中函数的定义如下所示。

实际使用过程中, 三种方式没有什么区别,根据自己的喜好去使用就可以。

函数使用场景一般是在bash脚本中,定义函数,然后进行调用。
同时也推荐,bash 脚本中需要使用的函数全部定义到一个单独的文件中,然后在bash脚本中进行引用。这样做的好处就是不光这一个bash脚本可以引用该文件里面的函数,其他的bash脚本也可以引用里面的某些函数。CentOS典型的例子有很多,例如/etc/init.d/functions文件。
然后在bash脚本中进行调用
bash中有两种返回值 函数执行结果返回值,使用echo命令返回,相当于Java 中的return关键字。 函数的退出状态码,默认是函数体最后一条命令的退出状态码。当然也可以自定义,使用return关键字。自定义退出状态码,其格式为: return 从函数中返回,用最后状态命令决定返回值。 return 0 无错误返回 return 1-255 有错误返回
bash 中函数支持参数的传递。但是与其他高级编程语言不同的是,bash中并不会显示的指定参数的类型和个数,而是直接在函数的最后的传入参数。与bash脚本的参数传递是一致的。 在函数体中当中,可使用$1, $2, …调用这些参数;还可以使用$@, $*, $#等特殊变量。这一点与bash脚本几乎一致。
因为bash的写法太过于灵活,以至于让人感觉bash并不是很严谨,在使用的时候可能要抛弃以往那些高级编程语言的思维。上面示例的结果如下图所示。
bash中的变量的作用域有三种类型: 环境变量:在当前shell和子shell中有效。 本地变量:只在当前shell进程中有效。 局部变量:只在函数的生命周期中有效。函数运行结束,变量失效。
在函数中定义局部变量的的方式是 <code>local VARIABLE_NAME=VALUE</code>
函数的递归调用指的是,函数间接地或者直接地调用自身。但是在递归地同时一定要注意什么时候结束递归,避免死循环。 这是编程地一种基本能力。

实验一 实现斐波那契数列

斐波那契数列又称黄金分割数列,因数学家列昂纳多·斐波那契以兔子繁殖为例子而引入,故又称为“兔子数列”,指的是这样一个数列:0、1、1、2、3、5、8、13、21、34、……,斐波纳契数列以如下被以递归的方法定义:F(0)=0,F(1)=1,F(n)=F(n-1)+F(n-2)(n≥2)利用函数,求n阶斐波那契数列

实验二 实现汉诺塔

汉诺塔(又称河内塔)问题是源于印度一个古老传说。大梵天创造世界的时候做了三根金刚石柱子,在一根柱子上从下往上按照大小顺序摞着64片黄金圆盘。大梵天命令婆罗门把圆盘从下面开始按大小顺序重新摆放在另一根柱子上。并且规定,在小圆盘上不能放大圆盘,在三根柱子之间一次只能移动一个圆盘,利用函数,实现N片盘的汉诺塔的移动步骤。

实验三 fork炸弹

fork 炸弹是一种恶意地程序。实质上是一个简单地递归程序,由于程序是递归的,如果没有任何限制,这会导致这个简单的程序迅速耗尽系统里面的所有资源。
顺便附上前几年比较火的让浏览器瞬间崩溃的12行代码,其实原理与fork炸弹是类似的。
bash 中没有像其他高级编程语言那么多的基本数据类型(int double)和引用数据类型(List ArrayList)。bash是一种弱类型的编程语言。 数组是存储多个元素的连续的内存空间,相当于多个变量的集合。
数组的声明有两种方式 显示声明:<code>declare -a ARRAY_NAME</code> 直接赋值:<code>ARRAY_NAME[INDEX]=VALUE</code> ,如果使用这种方式,Bash会自动创建数组。
数组的赋值有多种方式 一次只赋值一个元素 <code>ARRAY_NAME[INDEX]=VALUE</code> 一次赋值全部元素 <code>ARRAY_NAME=("VAL1" "VAL2" "VAL3" ...)</code> 只赋值特定元素 <code>ARRAY_NAME=([0]="VAL1" [3]="VAL2" ...)</code>
在介绍了数组的引用之后,一并来举例说明数组的使用。

注意:索引可支持使用自定义的格式,而不仅是数值格式,即为关联索引,bash4.0版本之后开始支持,这就是关联数组,有点类似于高级编程语言中的字典

数组的引用有下面几种方式 <code>${ARRAY_NAME[INDEX]}</code>省略[INDEX]表示引用下标为0的元素 引用所有的元素 <code>${ARRAY_NAME[*]}</code>,<code>${ARRAY_NAME[@]}</code> 数组的长度 <code>${#ARRAY_NAME[*]}</code> ,<code>${#ARRAY_NAME[@]}</code> 删除数组中的某个元素:导致稀疏格式 ,<code>unset ARRAY[INDEX]</code> 删除整个数组:<code>unset ARRAY</code>
数组数据的处理涉及到了数组数据的读取和追加。 数组切片 <code>${ARRAY[@]:offset:number}</code> offset :要跳过的元素个数 number:要取出的元素个数 区偏移量之后的所有元素 <code>${ARRAY[@]:offset}</code> 向数组中追加元素 <code>ARRAY[${#ARRAY[*]}]=value</code>

实验一 实现矩阵转置

这里我们需要注意的是,在bash中并没有二维数组的这个概念。所以我们只能够使用自定义下标的方式来模拟二维数组,原理上是相似的。 实现效果如下图所示。

实验二 编写脚本,定义一个数组,数组中的元素是/var/log目录下所有以.log结尾的文件;要统计其下标为偶数的文件中的行数之和

迄今为止,bash编程的大部分知识都已经介绍的差不多了,但是介绍的内容比较浅显,并没有深入的介绍。同时bash编程由于具有巨大的灵活性,导致使用方式多种多样,实际生产中应该根据自己的实际情况来灵活使用。

     本文转自Eumenides_s 51CTO博客,原文链接:http://blog.51cto.com/xiaoshuaigege/1965109,如需转载请自行联系原作者