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

相关推荐

  • N26-第九周

    1、写一个脚本,判断当前系统上所有用户的shell是否为可登录shell(即用户的shell不是/sbin/nologin);分别这两类用户的个数;通过字符串比较来实现; #!/bin/bash # # # NUM1=0 NUM2=0 for i in `cut -d: -f7 /etc/passwd` ;do if [[ “$i” = ‘/bin/bash…

    Linux干货 2017-03-15
  • nmcli及网络配置

    2017-09-10
  • 常见的文本处理工具及正则表达式的相关知识

    1.cat命令使用详解 cat [option]… [file]… -A equivalent=vET -b 非空行编号 -E 行为显示$ -n 显示所有行的行号 -s 行号并压缩连续空行为一行 -T 显示tab为^M 实例:显示a文件的行号及所有控制符 2.(1)head使用详解 head -n x 显示前x行 head -c x …

    Linux干货 2016-08-07
  • 文件的查找

    文件的查找 使用locate命令 默认从根开始搜索 非实时查找(数据库查找) locate 文件名 查询系统上预建的的文件索引数据库    /var/lib/mlocate/mlocate.db 依赖于事先构建的索引 索引的构建是在系统较为空闲时自动进行(周期性任务),管理员手动更新数据库(updatedb)。注意工作中不能轻易…

    Linux干货 2016-08-18
  • linux 启动管理

    1、Linux系统启动流程:POST 加电自检 — BIOS(Boot Sequence)–>MBR(bootloader,446)(加载前512字节后的驱动程序,进入/boot目录,加载内核)–>Kernel–>initrd–>(系统根路径 /)(ROOTFS)/sbin/…

    Linux干货 2017-09-03
  • Linux基础知识之文本查找和正则表达式扩展正则表达式

    1.什么是正则表达式?      正则表达式就是处理字符串的方法,它是以行为单位来进行字符串的处理行为,正则表达式通过一些特殊符号的复制,让用户可以轻易达到查找、删除、替换某些特定字符串的处理程序。      正则表达式基本上是一种“表示法”,只要工具程序支持这种表示法,那么该工作程序就可以用来作为…

    Linux干货 2016-08-10