脚本之循环的特殊用法及函数的使用

一、本文主要时针对while for select循环结果的特殊用法进行讲解。

    1、while循环的特殊用法

                while read line ;do    

                        循环体

                done < /path/from/somefile

          功能:依次从输入重定向的文件中读取每一行的内容复制给变量line,然后我们可以在循环体中执行对$line的操作,

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

#!/bin/bash
#
while read line
do
        zhushi=`echo $line | cut -d: -f5`
        userName=`echo $line | cut -d: -f1`
        if [[ -z $zhushi ]];then
                chfn -f $userName $userName &> /dev/null
                chfn -p 62985600 $userName &> /dev/null
                echo "$userName :信息修改成功"
        fi
done < /testdir/passwd

   

    2、for循环的特殊用法

            for ((i=1;i<100;i++))

            do

                        循环体

            done

        注意:此处for循环的使用类似与c语言的语法,但是不同的是此处需要的是双括号。

    

    3、select循环的特殊用法

                select 变量 in 参数…

                do

                        循环体命令

                done

        功能:将多个参数依次付给变量,并在屏幕上依次按照编号从1-n把参数显示出来,并根据选择的编号,来选择指定的参数,通常我们配合case 变量 in 来使用,因为select 是个死循环,因此需要借助break或者exit退出循环体,且可以省略in 参数,此时使用位置参数,PS3 可以定义选择提示符,用户输入编号被保存在内置变量REPLY中。

        应用举例:可以参照下面服务脚本/root/bin/testsrv.sh

二、函数的用法

            函数也由多条命令堆积组合在一起组成,我们可以将一些简单的,需要重复使用的命令组合起来写成函数,然后直接调用即可,这样避免了,我们重复编写代码,可提高效率。

            脚本也是有多个命令堆积组合而成,那么他们有什么区别呢?当我们在一个脚本中调用一个脚本时,我们相当于又重新开启了一个子shell,当我们定义一个函数并调用该函数时,相当于之当前shell中运行的,在当前shell中定义的变量,可以在函数中调用和访问的,且函数不能独立运行,必须调用时才能执行,在函数中定义变量最好定义局部变量,避免与脚本中的命令相同的本地变量发生冲突。

            定义函数:

                    语法1:

                                function f_name {

                                        …函数体…

                                }

                     语法2:

                                f_name() {

                                        …函数体…

                                }

        定义一个函数,在一个文件中定义一个文件不一定必须时.sh结尾的 只要是文本文件即可,然后写一个脚本,然后调用该函数

        函数的定义和使用:

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

            可以将函数放在脚本中作为它的一部分,直接调用函数名,即可执行函数内部的代码

            可放在只包含函数的单独文件中,通过source filename 就可以将函数读到指定的shell中,便于后续我们调用一些功能模块

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

         函数有两种返回值:

                使用echo或printf命令的输出结果

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

         函数的退出状态码:

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

                自定义退出状态码,其格式:

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

                    return 0 无错返回

                    return 1-255 有错返回

                    —-等同于脚本中的break功能

        当我们在命令行中定义了一个命令时,可以通过set命令查看该函数,也可通过unset  函数名 取消该函数。

        在脚本中定义函数时,必须要在引用脚本之前定义函数,否则会由于查找不到函数体,而报错。

        函数也可以接受位置变量

        函数的递归:(自己调用自己)

                函数直接或间接引用自身  

                应用举例:n!=n(n-1)(n-2)…1

#!/bin/bash
#
fact() {
if [ $1 -eq 0 -o $1 -eq 1 ]; then
echo 1         #当$1=1时fun函数通过echo输出的结果
else
echo $[$1*$(fact $[$1-1])]
fi
}
fact 5  每次输出调用函数fact 知道等$=1 才会有输出结果

        

            

1、写个脚本:

     *
   ***
 ******
********

#!/bin/bash
#
read -p "please input the longs:" long
for hang in `seq 1 $long`;do
        spaceNum=$[long-hang]
        xingNum=$[hang*2-1]
        for spacenum in `seq $spaceNum`;do
                echo -n " " 
        done
        for xingnum in `seq $xingNum`;do
                echo -n "*"
        done
echo
done
root@cenots6.8  /testdir # ./jinzita.sh 
please input the longs:4
   *
  ***
 *****
*******

2、用until循环实现国际象棋棋盘

declare -i hang=1
until [ $hang -gt 8 ];do
        lie=1
        until [ $lie -gt 8 ];do
                z=$[lie%2]
                if [ $z -eq 0 ];then
                        [[ $hang%2 -eq 0 ]] && echo -ne "\033[43m" "" "\033[0m" || echo -ne "\033[41m" "" "\033[0m"
                else
                        [[ $hang%2 -eq 0 ]] && echo -ne "\033[41m" "" "\033[0m" || echo -ne "\033[43m" "" "\033[0m"
                fi
        let lie++
        done
echo
let hang++
done

1、写一个服务脚本/root/bin/testsrv.sh,完成如下要求

(1) 脚本可接受参数: start, stop, restart, status

(2) 如果参数非此四者之一,提示使用格式后报错退出

(3) 如是start:则创建/var/lock/subsys/SCRIPT_NAME, 并显示“启动成功”考虑:如果事先已经启动过一次,该如何处理?

(4) 如是stop:则删除/var/lock/subsys/SCRIPT_NAME, 并显示“停止完成”考虑:如果事先已然停止过了,该如何处理?

(5) 如是restart,则先stop, 再start考虑:如果本来没有start,如何处理?

(6) 如是status, 则如果/var/lock/subsys/SCRIPT_NAME文件存在,则显示 SCRIPT_NAME is running…”如果/var/lock/subsys/SCRIPT_NAME文件不存在,则显示“ SCRIPT_NAME is stopped…”其中: SCRIPT_NAME为当前脚本名

#!/bin/bash
#
baseName=$(basename $0|cut -d"." -f1)
fileName=/var/lock/subsys$baseName
PS3="请输入您要选择的编号:"
select menu in start stop restart status
do
        case $menu in
        start)
                if [ -f $fileName ];then
                        echo "功能已经启动,如需重新启动,请选择 restart "
                else
                         touch $fileName
                        echo "启动成功"
                fi
                ;;
        stop)
                if [ -f $fileName ];then
                        rm -rf $fileName
                        echo "停止完成"
                else
                        echo "该功能已经停止,无需再次停止"
                fi
                ;;
        restart)
                rm -rf $fileName
                echo "停止完成"
                touch $fileName
                echo "启动成功"
                ;;
        status)
                [ -f $fileName ] && echo "$baseName is running..." || echo "$baseName is stoped..."
                ;;
        *)
                echo "您输入的信息有误"
                exit 1
                ;;
        esac
done
root@cenots6.8  /testdir # ./testsrv.sh 
1) start
2) stop
3) restart
4) status
请输入您要选择的编号:1
启动成功
请输入您要选择的编号:1
功能已经启动,如需重新启动,请选择 restart 
请输入您要选择的编号:2
停止完成
请输入您要选择的编号:2
该功能已经停止,无需再次停止
请输入您要选择的编号:3
停止完成
启动成功
请输入您要选择的编号:4
testsrv is running...
请输入您要选择的编号:5
您输入的信息有误

2、编写一个脚本/root/bin/copycmd.sh
(1) 提示用户输入一个可执行命令名称;
(2) 获取此命令所依赖到的所有库文件列表
(3) 复制命令至某目标目录(例如/mnt/sysroot)下的对应路径下;
如: /bin/bash ==> /mnt/sysroot/bin/bash
/usr/bin/passwd ==> /mnt/sysroot/usr/bin/passwd
(4) 复制此命令依赖到的所有库文件至目标目录下的对应路径下:
如: /lib64/ld-linux-x86-64.so.2 ==> /mnt/sysroot/lib64/ld
linux-x86-64.so.2
(5)每次复制完成一个命令后,不要退出,而是提示用户键入新的要复制的命
令,并重复完成上述功能;直到用户输入quit退出

#!/bin/bash
read -p "请输入一个可执行的命令:" Cmd
[ -z $Cmd ] && echo "输入信息不能为空" && exit 1

destDir=/mnt/sysroot
[ -d $destDir ] || mkdir $destDir

while [[ $Cmd != quit ]];
do

        cmdDir=`which $Cmd`  #取得命令二进制路径
        libDir=$(ldd `which cat` | sed -n "3p"|tr -d [[:space:]] | sed -r 's@(^/.*)\(.*\)$@\1@g') #取得库文件的路径
        cmddirName=`dirname $destDir$cmdDir` #取得命令的路径名 
        mkdir -p $cmddirName             #创建目录
         cp -r $cmdDir $destDir$cmdDir  #复制二进制文件到目标目录中
         echo "复制$destDir$cmdDir 完成"
            
        libdirName=`dirname $destDir$libDir`
        mkdir -p $libdirName
         cp -r $libDir $destDir$libDir
         echo "复制$destDir$libDir 完成"

         read -p "请重新输入新的要复制的命令:" Cmd
         [ -z $Cmd ] && echo "输入信息不能为空" && exit 1 
done
root@cenots6.8  /testdir # ./copycmd.sh 
请输入一个可执行的命令:cut
复制/mnt/sysroot/bin/cut 完成
复制/mnt/sysroot/lib64/ld-linux-x86-64.so.2 完成
请重新输入新的要复制的命令:getent
复制/mnt/sysroot/usr/bin/getent 完成
复制/mnt/sysroot/lib64/ld-linux-x86-64.so.2 完成
请重新输入新的要复制的命令:quit
root@cenots6.8  /testdir #
root@cenots6.8  /testdir # /mnt/sysroot/bin/c
cat  cut  
root@cenots6.8  /testdir # /mnt/sysroot/bin/c
cat  cut  
root@cenots6.8  /testdir # /mnt/sysroot/bin/cut -d":" -f1 /etc/passwd
root
bin
daemon

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

#!/bin/bash
#
function max(){
        [ $1 -lt $2 ] && max=$2 && echo "最大值为:$2"
}

max $1 $2
root@cenots6.8  /testdir # ./fun3.sh 1 3
最大值为:3

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

#!/bin/bash
#
function jia(){
        let Sum=$1+$2
        echo "和为:$Sum"
}

function jian(){
        let Cha=$1-$2
        echo "差为:$Cha"
}

function cheng(){
        let Ji=$1*$2
        echo "乘积为:$Ji"
}

function chu(){
        let Shang=$1/$2
        echo "商为:$Shang"
}
#!/bin/bash
source testfun.sh
jia $1 $2
jian $1 $2
cheng $1 $2
chu $1 $2
root@cenots6.8  /testdir # ./testfuns.sh 9 3
和为:12
差为:6
乘积为:27
商为:3

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

#!/bin/bash
#
function feibonaqie() {
        if [ $1 -eq 0 ];then
                echo 0
        elif [ $1 -eq 1 ];then
                echo 1
        else
                echo $[$1+`feibonaqie $[$1-1]`+`feibonaqie $[$-2]`]
        fi
}
feibonaqie $1
root@cenots6.8  /testdir # ./feibonaqie.sh 3
6

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

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

(1)
NarutoNaruto
上一篇 2016-08-21
下一篇 2016-08-21

相关推荐

  • shell编程的常见实例

    1. 写一个脚本/root/bin/argsnum.sh 用户输入一个文件路径并查找文件中空白行的个数 ,如果用户没有输入路径则自动退出  实验结果如下: 如果不输入任何路径程序会自动退出:实验结果如下: 用其他方法验证是不是有两行空行: (个人总结): 1.   read 命令,如果用 -p 来做提示信息,则不支持\n换行,这…

    Linux干货 2016-08-12
  • Hadoop Hive sql语法详解

    Hive 是基于Hadoop 构建的一套数据仓库分析系统,它提供了丰富的SQL查询方式来分析存储在Hadoop 分布式文件系统中的数据,可以将结构 化的数据文件映射为一张数据库表,并提供完整的SQL查询功能,可以将SQL语句转换为MapReduce任务进行运行,通过自己的SQL 去查询分析需 要的内容,这套SQL 简称Hive SQL,使不熟悉mapredu…

    Linux干货 2015-04-13
  • 软件包管理详解

      软件包管理器 1、功能: (1)将软件包打包成一个文件,其中包括: ①二进制程序 ②库文件 ③配置文件 ④帮助文件 (2)生成数据库,追中所安装的每一个文件。 2、软件包管理器的核心功能: (1)制作软件包 (2)安装、卸载、升级、查询、校验 3、不同发行版的不同的…

    2017-08-11
  • nmcli及网络配置

    2017-09-10
  • nginx

    1.Nginx的程序架构:        master/worker            一个master进程:     &nb…

    2017-06-19
  • LVM应用概要

    LVM — 即Logical Volume  Manager(逻辑卷管理管理),是Linux的一种磁盘管理机制。 LVM可以将物理磁盘以PV(Physical Volume)为单位抽象成VG(Volume Group)。在VG中,最小存储单元是一个PE(Physical Extent)。在VG的基础上再抽象一层,划分出LV(Logical Vol…

    2017-11-28