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

相关推荐

  • 逻辑卷管理器(LVM)-介绍

    逻辑卷管理器(LVM) §·逻辑卷管理器LVM介绍 2 ※·LVM逻辑卷的简单描述 2 ※·LVM逻辑卷的好坏 2 ※·LVM结构组成部分 2 §·LVM的举例分析 3 ※·LVM设备名称 3 ※·LVM分区类型: 3 ※·LVM  PV相关命令 3 ※·LVM  VG相关命令 3 ※·LVM  LV 相关命令 3 ※·LVM …

    Linux干货 2016-08-29
  • vim基本总结

    ASCII可以将计算机存储的0或1转成我们认识的文字。在Linux中,绝大部分的配置文件都是以ASCII的纯文本形态存在。通过文本编辑器,可以实现对这些文本文件的更改。常风的文本编辑器有emacs, pico,nano,joe与vi(vim是vi的升级版)等。那么为会么要学vi呢? l 因为vi是内置编辑器,系统安装好就有了 l 很多软件…

    2017-08-05
  • lvm基本应用

    前言 一种技术要知其然,还要知其所以然 lvm简介 LVM是 Logical Volume Manager(逻辑卷管理)的简写,它是Linux环境下对磁盘分区进行管理的一种机制。普通的磁盘分区管理方式在逻辑分区划分好之后就无法改变其大小,当一个逻辑分区存放不下某个文件时,这个文件因为受上层文件系统的限制,也不能跨越多个分区来存放,所以也不能同时放到别的磁盘上…

    Linux干货 2016-05-21
  • nginx配置文件中文文档

    Nginx配置参数中文说明。 #定义Nginx运行的用户和用户组user www www; #nginx进程数,建议设置为等于CPU总核心数。worker_processes 8; #全局错误日志定义类型,[ debug | info | notice | warn | error | crit ]error_log /var/log/nginx/error…

    Linux干货 2017-08-08
  • LVS NAT模型演示

    LVS NAT模型演示 这里我们刻意将两个RS的web页面文件,提供为不同的内容(实际应用中,每个RS页面的内容要完全相同) 基本配置 [root@web1 ~]# route add default gw 192.168.110.130  –> web1服务器…

    2016-10-29
  • Linux路由实验

    一    实验背景:路由器的功能是将不同网段的主机建立通信,本次试验是在使用linux主机当作路由器,完成主机间通信。如下图所示 二、实验环境:主机A和B为CentOS7.2,主机C和D为CentOS6.8,且C和D上分别都有两块网卡 三、实验步骤     注意:为避免干扰项,需将每台主机…

    Linux干货 2016-09-07