Shell脚本编程—特殊用法(select)及函数、递归

Shell脚本编程—特殊用法及函数

 

一、while的特殊用法:

1、使用格式:

while read 变量名;do

   循环体

done </PATH/TO/filename

注:依次从指定的文件中的内容逐行读取,并把读取到的每行赋值给变量。

2、例题:

扫描/etc/passwd文件每一行,如发现GECOS字段为空,则填充用户名和单位电话为13800138000,并提示该用户的GECOS信息修改成功。

如下图,修改前:

blob.png

如下图,修改后及代码:(如果不需要操作过程的信息,可在代码行“chfn后面添加/dev/null”)

脚本代码:

blob.png

blob.png 

二、双小括号的使用(类似C语言的编写风格):

1、双小括号方法,可以使bash Shell实现C语言风格的变量操作;也可以用于算术运算,(())格式,

#I=10

#((I++))

for循环的特殊格式:

for ((控制变量初始化;条件判断表达式;控制变量的修正表达式));do

循环体

done

   控制变量初始化:仅在运行到循环代码段时执行一次

   控制变量的修正表达式:每轮循环结束会先进行控制变量修正运算,而后再做条件判断

2、例题:做九九乘法

  脚本代码:

 blob.png

  代码及效果图:

 blob.png

三、select菜单的特殊使用:

1、使用格式:

selec t  variable  in  list ;do

循环体命令

done

2select 循环主要用于创建菜单,按数字顺序排列的菜单项将显示在标准错误上,并显示PS3 提示符,等待用户输入;用户输入菜单列表中的某个数字,执行相应的命令;用户输入被保存在内置变量REPLY 中。

3selectcase的结合使用:

select 是个无限循环,因此要记住用break 命令退出循环,或用exit 命令终止脚本。也可以按ctrl+c 退出循环。

 select 经常和case 联合使用

 for 循环类似,可以省略in list ,此时使用位置参量($*$@……)

4、例题:做一个脚本文件初始创建的模板

  如下,为脚本代码、执行步骤及效果图:

 blob.png

四、函数:

1、函数function是由若干条shell命令组成的语句块,实现代码重用和模块化编程。

2、函数与shell的对比:

它与shell程序形式上是相似的,不同的是它不是一个单独的进程,不能独立运行,而是shell程序的一部分。

3、函数和shell程序比较相似,区别在于:

   Shell程序在子Shell中运行

  Shell函数在当前Shell中运行。因此在当前Shell中,函数可以对shell中变量进行修改

4、认识函数的使用格式:函数由两部分组成:函数名和函数体。

  语法一:

function f_name{

函数体

}

  语法二:

function f_name(){

函数体

}

  语法三:

f_name(){

函数体

}

5、函数的定义和使用:

可在交互式环境下定义函数

可将函数放在脚本文件中作为它的一部分

可放在只包含函数的单独文件中

  调用:函数只有被调用才会执行;

调用:给定函数名

函数名出现的地方,会被自动替换为函数代码

 函数的生命周期:被调用时创建,返回时终止

6、简单认识函数:如下图

定义该函数add后,若在#后面键入add,其显示结果同ls-l的作用相同。删除定义的函数命令是:#unset add

 blob.png

 blob.png

注意:脚本内的$1$2变量与函数add内的$1$2是不一样的,要区分开来。

7、脚本内的函数调用:

函数在使用前必须定义,因此应将函数定义放在脚本开始部分,直至shell首次发现它后才能使用

  调用函数仅使用其函数名即可。

   如下图:

   blob.png

  注意,下图中的变量不能够放在函数的前面,否则函数无法使用和调用赋值计算:

 blob.png

8、写一个专门存放函数的文本,提供给其他的程序调用:

  A、可以将经常使用的函数存入函数文件,然后将函数文件载入shell;件名可任意选取,但最好与相关任务有某种联系。例如:functions.main

  B、一旦函数文件载入shell,就可以在命令行或脚本中调用函数。可以使用set命令查看所有定义的函数,其输出列表包括已经载入shell的所有函数。

 blob.png

C、若要改动函数,首先用unset命令从shell中删除函数。改动完毕后,再重新载入此文件。

D、调用函数文本格式:函数文件已创建好后,要将它载入shell

  定位函数文件并载入shell的格式:

. filename source filename

  注意:此即<> <空格> <文件名;这里的文件名要带正确路径

 

  事例:

  方法一:

  blob.png

  方法二:

  blob.png

  方法三:shell进程里面的子shell调用同一个函数:

  blob.png

(注:函数可以接受参数,调用函数时,在函数名后面以空白分隔给定参数列表即可;例如“testfuncarg1 arg2 …”;在函数体中当中,可使用$1, $2, …调用这些参数;还可以使用$@, $*, $#等特殊变量)

9、函数的变量:

  A、变量作用域:

环境变量:当前shell和子shell有效

本地变量:只在当前shell进程有效,为执行脚本会启动专用子shell进程;因此,本地变量的作用范围是当前shell脚本程序文件,包括脚本中的函数。

局部变量:函数的生命周期;函数结束时变量被自动销毁

    注意:如果函数中有局部变量,如果其名称同本地变量,使用局部变量。

  B、在函数中定义局部变量的方法:local NAME=VALUE

    事例:局部变量的定义

    变量定义前:如下图,shell脚本里面的变量与函数里面的变量名同名的情况下,shell脚本的变量无效。

   blob.png

    变量定义后:

  blob.png

10、函数的两种返回值:

  A、函数的执行结果返回值:

  (1) 使用echoprintf命令进行输出

  (2) 函数体中调用命令的输出结果

  B、函数的退出状态码:(一般用于条件判断时,当满足条件时,结束函数进程)请见例题2

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

  (2) 自定义退出状态码,其格式为:

     return 从函数中返回,用最后状态命令决定返回值

     return 0 无错误返回。

     return 1-255 有错误返回

 

  例题:

  1、写一个函数实现两个数字做为参数,返回最大值

  blob.png

 2、写一个函数实现数字的加减乘除运算,例如输入1 + 2,,将得出正确结果

 blob.png

(如下图,需求不同,代码也不一样)

11、函数的递归:

  1、函数递归:函数直接或间接调用自身;但需要注意递归层数。

  2、递归实例:

    阶乘是基斯顿·卡曼于1808 年发明的运算符号,是数学术语

    一个正整数的阶乘(factorial)是所有小于及等于该数的正整数的积,并且有0的阶乘为1。自然数n的阶乘写作n!

    n!=1×2×3××n

    阶乘亦可以递归方式定义:0!=1n!=(n-1)!×n

    n!=n(n-1)(n-2)…1

    n(n-1)! = n(n-1)(n-2)!

3、示例:digui.sh

 blob.png

事例:

1、斐波那契数列又称黄金分割数列,因数学家列昂纳多·斐波那契以兔子繁殖为例子而引入,故又称为“兔子数列”,指的是这样一个数列:0112358132134、……,斐波纳契数列以如下被以递归的方法定义:F0=0F1=1Fn=F(n-1)+F(n-2)n2

写一个函数,求n阶斐波那契数列

代码和效果如下图:

从题目中可以得知,从2开始,后一个数值是前两个数值的之和;因此,$11时,值为1$12时,为0+1=1$13时,为1+1=1……

blob.png

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

利用函数,实现N片盘的汉诺塔的移动步骤

代码和效果如下图:

三根柱子分别为:ABC

如果没有圆盘,则输出为空;

如果只有一个圆盘,则可以直接从柱子A移动到移动C,所以echo $2—$4

如果有两个及以上的圆盘,第一步先要借助柱子Cn-1的圆盘移动到柱子B上,因此第一个递归ta $(($1-1)) $2 $4 $3ACB),所以是echo $2—-$4(第n个圆盘的移动);第二步是将第一步移动到柱子B上存放的n-1圆盘借助柱子A来调换到柱子C上,即是第二个递归ta $(($1-1)) $3 $2 $4,因此,所以是echo $2—-$4

blob.png

原创文章,作者:Aaron_wang,如若转载,请注明出处:http://www.178linux.com/37758

(2)
Aaron_wangAaron_wang
上一篇 2016-08-21
下一篇 2016-08-21

相关推荐

  • 网络管理总结

      在学习Linux的快两个月时间的这个阶段,我们学习到了网络的相关知识,哇,原来我们上网是需要这么多步骤的,玩了这么久的电脑,打开过无数网站还只是停留在以为打开网站只需要点点鼠标的层面,惭愧惭愧。学习了一周,终于了解了一些网络的基层结构和一些网络协议,下面是对这一周所学知识的一些总结,加强记忆和理解。还停留在以为打开一个网站只是动动鼠标…

    2017-09-02
  • 文件相关命令

    1、Linux上的文件管理类命令都有哪些,其常用的使用方法及其相关示例演示。 cp:copy 源文件:目标文件 单源复制:cp [OPTION]… [-T] SOURCE DEST 如果DEST不存在,则事先创建此文件,并复制源文件的数据流至DEST中 如果DEST存在: 如果DEST是非目录文件:则覆盖目标文件 如果DEST是目录文件:则先在D…

    Linux干货 2016-09-23
  • httpd服务归纳:浅谈I/O模型

    1. 四种理论的I/O模型      1) 调用者(服务进程):         阻塞:  进程发起I/O调用,如果调用为完成,进程被挂起休眠,不能再执行其他功能    …

    Linux干货 2015-05-27
  • 正则表达式以及Linux文本搜索工具grep

    一正则表达式 regual Expression  简称REGEXP 定义:由一类特殊字符以及文本字所编写的模式,其中有些字符不表示其字面意义,而用于统配和统配功能 分类:     基本正则表达式:BRE 贪婪模式(尽可能长地去匹配符合模式的内容     扩展表达式:E…

    Linux干货 2016-08-07
  • vim编辑器

                                                      &nbsp…

    Linux干货 2015-12-19
  • 第三周作业

    1. 列出当前系统上所有已经登录的用户的用户名,注意:同一个用户登录多次则显示一次即可。 who | cut -d' ' -f1 | sort -u 2. 取出最后登录当前系统的用户的相关信息 grep  "$(who …

    Linux干货 2016-12-19

评论列表(1条)

  • 马哥教育
    马哥教育 2016-08-21 21:14

    文章条理结构清晰,层次分明,图文并貌,需要注意的地方是,图片不够清晰。