shell脚本4——特殊循环和函数

循环的特殊用法:

1、while循环的特殊用法之遍历文件的每一行

while read line; do
    循环体
done < /PATH/FROM/SOMEFILE

依次读取/PATH/FROM/SOMEFILE文件中的每一行,将每一行赋值给变量line,从而实现对文件的增删改

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

#!/bin/bash
#description if user no gecos add something to gecos
#version 0.1
#author gaomeng
#date 20160819
#
while read line ; do
    gecos=`echo $line | cut -d: -f5`
    if [ -z $gecos ] &> /dev/null ; then
        username=`echo $line | cut -d: -f1`
        usermod -c "$username 62985600" $username
        echo "$username gecos is changed."
    fi
done < /etc/passwd
[root@CentOS6 bin]# getent passwd gao
gao:x:500:500::/home/gao:/bin/bash  //gecos段无信息
[root@CentOS6 bin]# addgecos.sh
abrt gecos is changed.
ntp gecos is changed.
postfix gecos is changed.
gdm gecos is changed.
tcpdump gecos is changed.
hlr gecos is changed.
gao gecos is changed.
hadoop gecos is changed.
test gecos is changed.
[root@CentOS6 bin]# getent passwd gao
gao:x:500:500:gao 62985600:/home/gao:/bin/bash  //gecos段有信息

2、C语言风格的for循环:

双小括号方法,即((…))格式,代替shell中的in LIST 菜单

单纯用(( ))也可重定义变量值,比如 a=5; ((a++))可将$a重定义为6

for 循环的C语言风格:

for ((控制变量的初始化; 退出此for循环的条件; 控制变量的修正表达式))
do
    循环体
done

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

控制变量的修正表达式:每轮循环结束会先进行控制变量修正运算,而后再做退出for循环的条件判断,若满足条件则退出循环,若不满足则继续循环

例如:打印99乘法表

#!/bin/bash
#description echo 9 * 9
#version 0.1
#author gaomeng
#date 20160819
#
for (( i=1 ; i<=9 ; i++ ))
do
    for (( j=1 ; j<=i ; j++ ))
    do
        echo -en "$j*$i=$[$i*$j]\t"
    done
    echo
done
[root@CentOS6 bin]# bash for99.sh
1*1=1
1*2=2    2*2=4
1*3=3    2*3=6     3*3=9
1*4=4    2*4=8     3*4=12    4*4=16
1*5=5    2*5=10    3*5=15    4*5=20    5*5=25
1*6=6    2*6=12    3*6=18    4*6=24    5*6=30    6*6=36
1*7=7    2*7=14    3*7=21    4*7=28    5*7=35    6*7=42    7*7=49
1*8=8    2*8=16    3*8=24    4*8=32    5*8=40    6*8=48    7*8=56    8*8=64
1*9=9    2*9=18    3*9=27    4*9=36    5*9=45    6*9=54    7*9=63    8*9=72    9*9=81

3、select循环与菜单

select variable in list
do
    循环体命令
done

a.select循环主要用于创建菜单,按数字顺序排列的示菜单项将显示在标准错误上,并显示PS3提示符,等待用户输入,用户也可在脚本中修改PS3提示符,使之更加人性化

b.用户输入菜单列表中的某个数字,执行数字后所相应的命令

c.用户输入被保存在内置变量REPLY中,可以在语句中打印此变量

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

e.select经常和case联合使用

f.与for循环类似,可以省略 in list,此时使用位置参量

例如:1.没有修改PS3提示符,也没有配合case语句使用

#!/bin/bash
#description show select
#version 0.1
#authre gaomeng
#date 20160819
#
select list in gongbaojiding hongshaorou huobaofeichang shaopaigu
do
    echo $list
done
[root@CentOS6 bin]# select.sh
1) gongbaojiding
2) hongshaorou
3) huobaofeichang
4) shaopaigu
#? 1
gongbaojiding
#? 2
hongshaorou
#? 3
huobaofeichang
#? 4
shaopaigu
#? 5
#? 6
#? ^C

2.修改了PS3,配合使用了case语句:

#!/bin/bash
#description show select
#version 0.3
#authre gaomeng
#date 20160819
#
PS3="What do you want:"
select list in gongbaojiding hongshaorou huobaofeichang shaopaigu
do
    case $list in
    gongbaojiding)
        echo "$list is 20¥"
        exit;;
    hongshaorou)
        echo "$list is 30¥"
        exit;;
    huobaofeichang)
        echo "$list is 25¥"
        exit;;
    shaopaigu)
        echo "$list is 40¥"
        exit;;
    *)
        echo "no the list, please choice other."
    esac
done
[root@CentOS6 bin]# select.sh
1) gongbaojiding
2) hongshaorou
3) huobaofeichang
4) shaopaigu
What do you want:1
gongbaojiding is 20¥
[root@CentOS6 bin]# select.sh
1) gongbaojiding
2) hongshaorou
3) huobaofeichang
4) shaopaigu
What do you want:4
shaopaigu is 40¥
[root@CentOS6 bin]# select.sh
1) gongbaojiding
2) hongshaorou
3) huobaofeichang
4) shaopaigu
What do you want:8
no the list, please choice other.
What do you want:3
huobaofeichang is 25¥

函数:

函数function是由若干条shell命令组成的语句块,实现代码重用和模块化编程,即有个功能或模块,我们在代码中会反复使用,则可以写成函数,使用是调用函数即可,而不用多次编写代码

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

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

     Shell程序在子Shell中运行

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

函数的定义:

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

定义:

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

     语法一:

     function f_name {

     … 函数体…

     }

     语法二:

     function f_name () {

     … 函数体…

     }

     语法三:

     f_name() {

     … 函数体…

     }

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

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

c.可放在只包含函数的单独文件中,在脚本中用source 和. 调用函数

d.可以将经常使用的函数存入函数文件,然后将函数文件载入shell

e.文件名可任意选取,但最好与相关任务有某种联系。例如:functions.main

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

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

载入函数:

shell脚本中调用一个已创建好函数文件:

. filename 或 source filename

注意:此处<点> <空格> <文件名>

这里的文件名要使用路径,绝对路径或者相对路径都可以

调用函数:

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

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

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

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

删除函数:

使用unset命令完成此功能.

unset function_name

函数的返回值:

函数的执行结果返回值:

     (1) 使用echo或printf命令进行输出

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

函数的退出状态码:

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

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

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

         return 0 无错误返回。

         return 1-255 有错误

函数参数:

函数可以接受参数:

传递参数给函数:调用函数时,在函数名后面以空白分隔给定参数列表即可;例如“testfunc arg1 arg2 …”

在函数体中当中,可使用$1, $2, … 调用这些参数;还可以使用$@, $*, $# 等特殊变量

注意:请区分函数中的$1和脚本的$1不同之处

例如:如下脚本

#!/bin/bash
#description test function $1 $2
#version 0.1
#author gaomeng
#date 20160819
#
prin() {
    echo "prin function \$1 is $1."
    echo "prin function \$2 is $2."
}

echo "\$1 is $1."
echo "\$2 is $2."
prin $2 $1
[root@CentOS6 bin]# functiontest.sh 3 9
$1 is 3.
$2 is 9.
prin function $1 is 9.
prin function $2 is 3.

函数变量:

变量作用域:

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

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

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

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

         在函数中定义局部变量的方法

             local NAME=VALUE

#!/bin/bash
#description
#version 0.1
#author gaomeng
#date 20160819
#
test1() {
    echo "test1 name=$name"   //没有定义变量
}
test2() {
    local name=haha   //定义了局部变量
    echo "test2 name=$name"
}
test3() {
    name=haha    //直接定义了一个变量,会影响脚本中的变量值?
    echo "test3 name=$name"
}
name=gaomeng
echo "name=$name"
test1
echo "name=$name"
test2
echo "name=$name"
test3
echo "name=$name"

[root@CentOS6 bin]# bash functiontest1.sh
name=gaomeng
test1 name=gaomeng        //函数中没有定义变量,则自动使用脚本中的同名变量
name=gaomeng
test2 name=haha
name=gaomeng            //在函数中定义的局部变量没有影响脚本中的变量
test3 name=haha         
name=haha            //在函数中定义的变量影响了脚本中的变量

函数递归:

函数直接或间接调用自身

注意递归层数

递归实例:

阶乘是基斯顿·于 卡曼于 1808  年发明的运算符号,是数学术语一个正整数的阶乘(factorial )是所有小于及等于该数的正整数的积,并且有0 的阶乘为1 。自然数n 的阶乘写作n!

    n!=1 ×2 ×3 ×… ×n

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

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

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


例:fact.sh

#!/bin/bash
#
fact() {
    if [ $1 -eq 0 -o $1 -eq 1 ]; then
        echo 1
    else
        echo $[$1*$(fact $[$1-1])]
    fi
}
fact 5

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

#!/bin/bash
#description input two number, and retuen max number.
#version 0.1
#author gaomeng
#date 20160818
#
max(){
    if [ $1 -gt $2 ]; then
        echo "max number is: $1"
    else
        echo "max number is: $2"
    fi
}

read -p "Input first number: " num1
until echo $num1 | grep -qE "^[0-9]+$";do
    read -p "your number error, Input first number: " num1
done
read -p "Input second number: " num2
until echo $num2 | grep -qE "^[0-9]+$";do
    read -p "your number error, Input second number: " num2
done

max $num1 $num2

[root@CentOS6 bin]# function3.sh
Input first number: sdf
your number error, Input first number: 123
Input second number: -124
your number error, Input second number: sdkf
your number error, Input second number: 100
max number is: 123

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

#!/bin/bash
#desription four arithmetic operation
#version 0.1
#author gaomeng
#date 20160818
#
operation() {
    if [ $2 == "+" ]; then
        echo "$1+$3=$[$1+$3]"
    elif [ $2 == "-" ]; then
        echo "$1-$3=$[$1-$3]"
    elif [ $2 == "x" ]; then
        echo "${1}x${3}=$[$1*$3]"
    elif [ $2 == "/" ]; then
        echo "$1/$3=$[$1/$3]"
    else
        echo "this is error symbol."
    fi
}

read -p "Input first number: " num1
until echo $num1 | grep -qE "^\-?[0-9]+$";do
    read -p "your number error, Input first number: " num1
done

i=0
until [ $i -eq 1 ];do
    read -p "Input operation symbol( please x instead of * ): " num2
    [ $num2 == "+" -o $num2 == "-" -o $num2 == "x" -o $num2 == "/" ] &> /dev/null &&i=1
done

read -p "Input second number: " num3
until echo $num3 | grep -qE "^\-?[0-9]+$";do
    read -p "your number error, Input second number: " num3
done

operation $num1 $num2 $num3
[root@CentOS6 bin]# function4.sh
Input first number: sdf
your number error, Input first number: 5
Input operation symbol( please x instead of * ): *
Input operation symbol( please x instead of * ): x
Input second number: -4
5x-4=-20

3、斐波那契数列又称黄金分割数列,因数学家列昂纳多·斐波那契以兔子繁殖为例子而引入,故又称为“兔子数列”,指的是这样一个数列: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 阶斐波那契数列

0  1   2   3   4   5   6   7    8    9

0、1 、1 、2 、3 、5 、8 、13 、21 、34

#!/bin/bash
#description series of rabbit
#version 0.3
#author gaomeng
#date 20160818
#
series() {
    if [ $1 -eq 0 ]; then
        sum=0
    elif [ $1 -eq 1 ];then
        sum=1
    else
        let sum=`series $[$1-1]`+`series $[$1-2]`
    fi
    echo "$sum"
}

read -p "Please input month number: " num
until echo $num | grep -qE "^[0-9]+$";do
    read -p "your number error, Input month number: " num
done

series $num
[root@CentOS6 bin]# function5.sh
Please input month number: -123
your number error, Input month number: sdf
your number error, Input month number: 8
21
[root@CentOS6 bin]# function5.sh
Please input month number: 1.02323
your number error, Input month number: 10
55

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

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

#!/bin/bash
#description hanoi game
#version 0.2
#author gaomeng
#date 20160818
#
i=1
move() {
    echo -e "$i)\t$1 plate from $2 to $3."
    let i++
}
hanoi() {
    if [ $1 -eq 1 ]; then
        move $1 $2 $4
    else
        hanoi $[$1-1] $2 $4 $3
        move $1 $2 $4
        hanoi $[$1-1] $3 $2 $4
    fi
}

read -p "Please input move plate numbers: " num
until echo $num | grep -qE "^[0-9]+$";do
    read -p "your number error, Input move plate number: " num
done

hanoi $num A B C
[root@CentOS6 bin]# function6.sh
Please input move plate numbers: 3
1)1 plate from A to C.
2)2 plate from A to B.
3)1 plate from C to B.
4)3 plate from A to C.
5)1 plate from B to A.
6)2 plate from B to C.
7)1 plate from A to C.
[root@CentOS6 bin]# function6.sh
Please input move plate numbers: 4
1)1 plate from A to B.
2)2 plate from A to C.
3)1 plate from B to C.
4)3 plate from A to B.
5)1 plate from C to A.
6)2 plate from C to B.
7)1 plate from A to B.
8)4 plate from A to C.
9)1 plate from B to C.
10)2 plate from B to A.
11)1 plate from C to A.
12)3 plate from B to C.
13)1 plate from A to B.
14)2 plate from A to C.
15)1 plate from B to C.

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

(0)
megedugaomegedugao
上一篇 2016-08-21
下一篇 2016-08-22

相关推荐

  • 源码包编译安装mariaDB

    前言     MySQL是一个关系型数据库管理系统,是最流行的关系型数据库管理系统,由于其体积小、速度快、总体拥有成本低,并且之前是完全开源,所以大受欢迎。但由于后面MySQL卖给了SUN,随后SUN被Oracle收购,虽然也有开源免费版本,但是很多功能都需要另外购买商业版本,导致现在MySQL使用份额逐渐减少。所以M…

    Linux干货 2016-02-28
  • N25第一周作业

    第一周作业 一、计算机由硬件系统和软件系统两部分组成如下: 计算机硬件由CPU、内存、输入设备、输出设备组成。 1、中央处理器(CPU,Central Processing Unit)   CPU的功能主要是对输入指令的判断和运算;CPU包括运算器、控制器和寄存器三部分; (1)、运算器   执行各种算术和逻辑运算操作,计算机运行时,运算…

    Linux干货 2016-12-05
  • KVM虚拟化平台部署及管理

    前言 KVM即Kernel Virtual Machine,最初是由以色列公司Qumranet开发。2007年2月被导入Linux 2.6.20核心中,成为内核源代码的一部分。2008年9月4日,Redhat收购了Qumranet,至此Redhat拥有了自己的虚拟化解决方案,之后便舍弃Xen开始全面扶持KVM,从RHEL6开始KVM便被默认内置于内核中。本文…

    Linux干货 2015-07-19
  • LVM 逻辑卷管理器

    1、什么是LVM:PV、PE、VG、LV的意义    LVM:Logical Volume Manager(逻辑卷管理器),可以将多个物理分区整合成看起来像一个磁盘一样,并可随意增加或减少逻辑卷大小 dm:device mapper,将一个或多个底层块设备组织成一个逻辑设备的模块; /dev/mapper/VG_NAME-LV_NAME …

    Linux干货 2016-09-19
  • nginx反向代理负载均衡集群配置详解

    反向代理负载均衡集群配置详解 反向代理(Reverse Proxy)方式是指以代理服务器来接受internet上的连接请求,然后将请求转发给内部网络上的服务器,并将从服务器上得到的结果返回给internet上请求连接的客户端,此时站在服务器角度来看,代理服务器对外就表现为一个反向代理服务器。 对反向代理服务器的攻击并不会使得后端内网Web服务器上网页信息遭到…

    Linux干货 2016-11-07
  • Linux 第一周总结

    一、描述计算机的组成及其功能。 计算机组成是由软件和硬件组成的。 硬件部分由cpu、主板、存储器、输入输出设备组成 Cpu:主要是解释计算机指令以及处理计算机软件中的数据。 主板:是微机最基本的也是最重要的部件之一,一般有BIOS芯片、I/O控制芯片、键和面板控制开关接口、指示灯插接件、扩充插槽、主板及插卡的直流电源供电接插件等元件。 存储器:是存储程序和各…

    2017-07-02