bash脚本之进阶

bash脚本

1、终端打印

1、单双引号(echo)

双引号:

①在双引号里面打不出!

bash脚本之进阶

②双引号,可以在文本中使用“;”,“;”在bash中被用作命令定界符。

bash脚本之进阶

单引号:

变量替换在单引号中无效。

bash脚本之进阶

2、printf:不会自动添加换行符,要手动添加

bash脚本之进阶

如下:

bash脚本之进阶

结果:

bash脚本之进阶

3、补充:

echo 要使用转义系列需要加e,!号除外

bash脚本之进阶

2、变量和环境变量

脚本语言通常不需要在使用变量之前声明变量类型,直接赋值就可以了。

Bash中,每一个变量的值都是字符串,无论变量赋值时有没有用引号,值都会以字符串形式存储。

1、查看某个进程的环境变量

env查看所有的环境变量

cat /proc/$PID/environ

bash脚本之进阶

有很多,截取一点,其中的环境变量用null字符"\0"连接,要想每行显示一个,可以将"\0"转化为"\n"。如下

bash脚本之进阶

2、变量赋值与引用

var=value(等号两边没有空格 var = value是错误的)

如果,value中不包含任何空白字符,就不需要用引号

变量名前加$就表示引用,可以在双引号中引用变量

bash脚本之进阶

bash脚本之进阶


环境变量是由父进程继承过来的,要用export来设置,设置后从当前shell脚本任务执行的应用程序都会继承这个变量。

比如PATH这个环境变量,就是查找文件时候的搜索路径,要在PATH中添加一条新的路径

PATH="PATH:/home/user/bin"
export PATH

bash脚本之进阶

使用单引号时变量不会被引用。

检测是否为超级用户:

bash脚本之进阶

数值比较
            -eq:是否等于; [ $num1 -eq $num2 ]
            -ne:是否不等于;
            -gt:是否大于;
            -ge:是否大于等于;
            -lt:是否小于;
            -le:是否小于等于;

字符串测试:
            ==:是否等于;
            >:是否大于;
            <:是否小于;
            !=:是否不等于;
            =~:左侧字符串是否能够被右侧的PATTERN所匹配;

            -z "STRING":判断指定的字串是否为空;空则为真,不空则假;
            -n "STRING":判断指定的字符串是否不空;不空则真,空则为假;

3、使用shell进行数学运算

算数操作用let、(())和[],bc是专门做运算的命令

bash脚本之进阶

使用let运算的后面的变量引用不用加$

计算1加到100的和:

bash脚本之进阶

自加let no1++ 或 let no+=6
自减let no1-- 或 let no-=6

[]的使用方法类let,(())也是。

bash脚本之进阶


bc是个高级的工具,可以计算浮点数和高级函数,以上都不支持浮点计算。

bash脚本之进阶

4、条件判断式

if [ ]; then
    command;
fi

或:
if [ ];then
    command1;
else
    command2;
fi

或:
if [ ] ;then
    command;
elif [ ];then
    command2;
else
    command3;
fi

通过参数传递一个用户名给脚本,此用户不存时,则添加之;且用户名为密码:

bash脚本之进阶

另外一种方法

bash脚本之进阶


练习2:通过命令行参数给定一个用户名,判断其ID号是偶数还是奇数;

bash脚本之进阶

练习3:通过命令行参数给定两个文本文件名,如果某文件不存在,则结束脚本执行;都存在时返回每个文件的行数,并说明其中行数较多的文件;

bash脚本之进阶

示例:脚本参数传递一个文件路径给脚本,判断此文件的类型;

                #!/bin/bash
                #
                if [ $# -lt 1 ]; then
                    echo "At least on path."
                    exit 1
                fi

                if ! [ -e $1 ]; then
                    echo "No such file."
                    exit 2
                fi

                if [ -f $1 ]; then
                    echo "Common file."
                elif [ -d $1 ]; then
                    echo "Directory."
                elif [ -L $1 ]; then
                    echo "Symbolic link."
                elif [ -b $1 ]; then
                    echo "block special file."
                elif [ -c $1 ]; then
                    echo "character special file."
                elif [ -S $1 ]; then
                    echo "Socket file."
                else
                    echo "Unkown."
                fi  

                注意:if语句可嵌套;

练习:写一个脚本

            (1) 传递一个参数给脚本,此参数为用户名;
            (2) 根据其ID号来判断用户类型:
                0: 管理员
                1-999:系统用户
                1000+:登录用户

                #!/bin/bash
                #
                [ $# -lt 1 ] && echo "At least on user name." && exit 1

                ! id $1 &> /dev/null && echo "No such user." && exit 2

                userid=$(id -u $1)

                if [ $userid -eq 0 ]; then
                    echo "root"
                elif [ $userid -ge 1000 ]; then
                    echo "login user."
                else
                    echo "System user."
                fi                                      

    练习:写一个脚本
            (1) 列出如下菜单给用户:
                disk) show disks info;
                mem) show memory info;
                cpu) show cpu info;
                *) quit;
            (2) 提示用户给出自己的选择,而后显示对应其选择的相应系统信息;

                #!/bin/bash
                #
                cat << EOF
                disk) show disks info
                mem) show memory info
                cpu) show cpu info
                *) QUIT
                EOF

                read -p "Your choice: " option

                if [[ "$option" == "disk" ]]; then
                    fdisk -l /dev/[sh]d[a-z]
                elif [[ "$option" == "mem" ]]; then
                    free -m
                elif [[ "$option" == "cpu" ]];then
                    lscpu
                else
                    echo "Unkown option."
                    exit 3
                fi

5、循环执行

    bash脚本:
        for循环
        while循环
        until循环

    for循环:
        两种格式:
            (1) 遍历列表
            (2) 控制变量

        遍历列表:
            for  VARAIBLE  in  LIST; do
                循环体
            done

            进入条件:只要列表有元素,即可进入循环;
            退出条件:列表中的元素遍历完成;

    LISTT的生成方式:
    (1) 直接给出; 
    (2) 整数列表
        (a) {start..end}
            如:{1..10}
        (b) seq [start  [incremtal]] last
        如: seq 6 16    生成从6到16的数字列表,可以指定步长。 seq 1 2 6
    (3) 返回列表的命令
    (4) glob 
    (5) 变量引用
        $@, $*
        ...



            示例:求100以内所有正整数之和;
                #!/bin/bash
                #
                declare -i sum=0

                for i in {1..100}; do
                    echo "\$sum is $sum, \$i is $i"
                    sum=$[$sum+$i]
                done

                echo $sum

            示例:判断/var/log目录下的每一个文件的内容类型
                #!/bin/bash
                #
                for filename in /var/log/*; do
                    if [ -f $filename ]; then
                        echo "Common file."
                    elif [ -d $filename ]; then
                        echo "Directory."
                    elif [ -L $filename ]; then
                        echo "Symbolic link."
                    elif [ -b $filename ]; then
                        echo "block special file."
                    elif [ -c $filename ]; then
                        echo "character special file."
                    elif [ -S $filename ]; then
                        echo "Socket file."
                    else
                        echo "Unkown."
                    fi                  
                done

练习:
    1、分别求100以内所有偶数之和,以及所有奇数之和;

bash脚本之进阶

    2、计算当前系统上的所有用的id之和;

bash脚本之进阶


示例:求100以内所有正整数之和;

        #!/bin/bash
        #
        declare -i sum=0
        declare -i i=1

        until [ $i -gt 100 ]; do
            let sum+=$i
            let i++
        done

        echo $sum           


        #!/bin/bash
        #
        declare -i sum=0
        declare -i i=1

        while [ $i -le 100 ]; do
            let sum+=$i
            let i++
        done

        echo $sum           

while:

    while  CONDITION; do
        循环体
         循环控制变量修正表达式
    done


    打印九九乘法表;

bash脚本之进阶


循环控制:

break:停止指定层循环
continue:跳过循环体中的剩余命令。

bash脚本之进阶

case

    示例1:显示一个菜单给用户;
        cpu) display cpu information
        mem) display memory information
        disk) display disks information
        quit) quit

        要求:(1) 提示用户给出自己的选择;
               (2) 正确的选择则给出相应的信息;否则,则提示重新选择正确的选项;

            #!/bin/bash
            #
            cat << EOF
            cpu) display cpu information
            mem) display memory infomation
            disk) display disks information
            quit) quit
            ===============================
            EOF

            read -p "Enter your option: " option

            while [ "$option" != "cpu" -a "$option" != "mem" -a "$option" != "disk" -a "$option" != "quit" ]; do
                echo "cpu, mem, disk, quit"
                read -p "Enter your option again: " option
            done

            if [ "$option" == "cpu" ]; then
                lscpu
            elif [ "$option" == "mem" ]; then
                free -m
            elif [ "$option" == "disk" ]; then
                fdisk -l /dev/[hs]d[a-z]
            else
                echo "quit"
                exit 0
            fi      

        case语句的语法格式:

            case  $VARAIBLE  in  
            PAT1)
                分支1
                ;;
            PAT2)
                分支2
                ;;
            ...
            *)
                分支n
                ;;
            esac

            case支持glob风格的通配符:
                *:任意长度的任意字符;
                ?:任意单个字符;
                []:范围内任意单个字符;
                a|b:a或b;

        示例:写一个服务框架脚本;
            $lockfile,  值/var/lock/subsys/SCRIPT_NAME

            (1) 此脚本可接受start, stop, restart, status四个参数之一;
            (2) 如果参数非此四者,则提示使用帮助后退出;
            (3) start,则创建lockfile,并显示启动;stop,则删除lockfile,并显示停止;restart,则先删除此文件再创建此文件,而后显示重启完成;status,如果lockfile存在,则显示running,否则,则显示为stopped.

                #!/bin/bash
                #
                # chkconfig: - 50 50
                # description: test service script
                #
                prog=$(basename $0)
                lockfile=/var/lock/subsys/$prog

                case $1  in
                start)
                    if [ -f $lockfile ]; then
                        echo "$prog is running yet."
                    else
                        touch $lockfile
                        [ $? -eq 0 ] && echo "start $prog finshed."
                    fi
                    ;;
                stop)
                    if [ -f $lockfile ]; then
                        rm -f $lockfile
                        [ $? -eq 0 ] && echo "stop $prog finished."
                    else
                        echo "$prog is not running."
                    fi
                    ;;
                restart)
                    if [ -f $lockfile ]; then
                        rm -f $lockfile
                        touch $lockfile
                        echo "restart $prog finished."
                    else
                        touch -f $lockfile
                        echo "start $prog finished."
                    fi
                    ;;
                status)
                    if [ -f $lockfile ]; then
                        echo "$prog is running"
                    else
                        echo "$prog is stopped."
                    fi
                    ;;
                *)
                    echo "Usage: $prog {start|stop|restart|status}"
                    exit 1
                esac

6、函数

过程式编程:代码重用
        模块化编程
        结构化编程 

        把一段独立功能的代码当作一个整体,并为之一个名字;命名的代码段,此即为函数;

        注意:定义函数的代码段不会自动执行,在调用时执行;所谓调用函数,在代码中给定函数名即可;

        函数名出现的任何位置,在代码执行时,都会被自动替换为函数代码;

    语法一:
        function  f_name  {
            ...函数体...
        }

    语法二:
        f_name()  {
            ...函数体...
        }

函数的生命周期:每次被调用时,创建函数,返回时终止,即函数代码引用完了,bash脚本每次都有一个状态返回值,函数也有返回值。在函数中使用echo打印的返回值,也有状态返回值。其状态返回结果为函数体中运行的最后一条命令的状态结果;

        自定义状态返回值,需要使用:return(终止),相当于exit。
            return [0-255]
                0: 成功
                1-255: 失败

示例:给定一个用户名,取得用户的id号和默认shell;
        #!/bin/bash
        #

        userinfo() {
            if id "$username" &> /dev/null; then
                grep "^$username\>" /etc/passwd | cut -d: -f3,7
            else
                echo "No such user."
            fi
        }

        username=$1
        userinfo

        username=$2
        userinfo            

    示例2:服务脚本框架
        #!/bin/bash
        #
        # chkconfig: - 50 50
        # description: test service script
        #
        prog=$(basename $0)
        lockfile=/var/lock/subsys/$prog

        start() {
            if [ -f $lockfile ]; then
                echo "$prog is running yet."
            else
                touch $lockfile
                [ $? -eq 0 ] && echo "start $prog finshed."
            fi
        }

        stop() {
            if [ -f $lockfile ]; then
                rm -f $lockfile
                [ $? -eq 0 ] && echo "stop $prog finished."
            else
                echo "$prog is not running."
            fi
        }
        status() {
            if [ -f $lockfile ]; then
                echo "$prog is running"
            else
                echo "$prog is stopped."
            fi
        }

        usage() {
            echo "Usage: $prog {start|stop|restart|status}"
        }

        case $1 in
        start)
            start ;;
        stop)
            stop ;;
        restart)
            stop
            start ;;
        status)
            status ;;
        *)
            usage
            exit 1 ;;
        esac


函数返回值:
        函数的执行结果返回值:
            (1) 使用echo或printf命令进行输出;
            (2) 函数体中调用的命令的执行结果;
        函数的退出状态码:
            (1) 默认取决于函数体中执行的最后一条命令的退出状态码;
            (2) 自定义:return

函数可以接受参数:
        传递参数给函数:
            在函数体中当中,可以使用$1,$2, ...引用传递给函数的参数;还可以函数中使用$*或$@引用所有参数,$#引用传递的参数的个数;
            在调用函数时,在函数名后面以空白符分隔给定参数列表即可,例如,testfunc  arg1 arg2 arg3 ...

        示例:添加10个用户,
            添加用户的功能使用函数实现,用户名做为参数传递给函数;

                #!/bin/bash
                #
                # 5: user exists

                addusers() {
                    if id $1 &> /dev/null; then
                        return 5
                    else
                        useradd $1
                        retval=$?
                        return $retval
                    fi
                }

                for i in {1..10}; do
                    addusers ${1}${i}
                    retval=$?
                    if [ $retval -eq 0 ]; then
                        echo "Add user ${1}${i} finished."
                    elif [ $retval -eq 5 ]; then
                        echo "user ${1}${i} exists."
                    else
                        echo "Unkown Error."
                    fi
                done

    练习:写一个脚本;
        使用函数实现ping一个主机来测试主机的在线状态;主机地址通过参数传递给函数;
        主程序:测试172.16.1.1-172.16.67.1范围内各主机的在线状态;

    练习:写一个脚本;
        打印NN乘法表;

    变量作用域:
        局部变量:作用域是函数的生命周期;在函数结束时被自动销毁;
            定义局部变量的方法:local VARIABLE=VALUE
        本地变量:作用域是运行脚本的shell进程的生命周期;因此,其作用范围为当前shell脚本程序文件;

        示例程序:
            #!/bin/bash
            #
            name=tom

            setname() {
                local name=jerry
                echo "Function: $name"
            }

            setname
            echo "Shell: $name"

函数递归:
        函数直接或间接调用自身;

        10!=10*9!=10*9*8!=10*9*8*7!=...
            n
                n*(n-1)!=n*(n-1)*(n-2)!=

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

            fact $1                 


        1,1,2,3,5,8,13,21,...

            #!/bin/bash
            #
            fab() {
                if [ $1 -eq 1 ]; then
                    echo -n "1 "
                elif [ $1 -eq 2 ]; then
                    echo -n "1 "
                else
                    echo -n "$[$(fab $[$1-1])+$(fab $[$1-2])] "
                fi
            }

            for i in $(seq 1 $1); do
                fab $i
            done
            echo

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

(0)
上一篇 2016-11-28 21:59
下一篇 2016-11-28 23:59

相关推荐

  • Hadoop HDFS分布式文件系统设计要点与架构

    Hadoop简介:一个分布式系统基础架构,由Apache基金会开发。用户可以在不了解分布式底层细节的情况下,开发分布式程序。充分利用集群的威力高速运算和存储。Hadoop实现了一个分布式文件系统(Hadoop Distributed File System),简称HDFS。HDFS有着高容错性的特点,并且设计用来部署在低廉的(low-cost)硬件…

    Linux干货 2015-04-13
  • N22-第六周作业

    vim小小的总结 (本总结摘自马哥网络班22期课堂笔记) vim是一款交互式的全屏编辑器,是vi的升级版,在vi上增强了很多,如:多级撤销,多窗口和多缓冲区,语法高亮,在线帮助等。 vim也是一种模式化的编辑器。分别是编辑模式也叫命令模式,输入模式,末行模式。其中使用vim打开文件后默认的是编辑模式。 三种模式之间的转换: 编辑模式—>输入模式 &…

    Linux干货 2016-11-21
  • Linux文件查找之locate、find详解

     locate命令详解 locate命令其实是find -name的另一种写法,但是要比后者快得多,原因在于它不搜索具体目录,而是搜索一个数据库文件,这个数据库中含有本地所有文件信息。Linux系统自动创建这个数据库,并且每天自动更新一次,所以使用locate命令查不到最新变动过的文件。为了避免这种情况,可以在使用locate之前,先使用updat…

    Linux干货 2016-08-16
  • 提问的智慧

    译文 译文: 捷克语 丹麦语 爱沙尼 亚语 法语 德语 希伯来语 匈牙利语 意大利语 日语 波 兰语 俄语 西班牙语 瑞典语 土 耳其语. 如果你想复制、镜像、翻译或引用本文,请参阅我的 复制须知. 弃权申明 …

    Linux干货 2015-03-20
  • 实现基于MYSQL验证的vsftpd虚拟用户

    马哥教育面授21期 运维 vsftpd MySQL 说明:本实验在两台CentOS主机上实现,一台做为FTP服务器,一台做数据库服务器 一、安装所需要包和包组: 在数据库服务器上安装包: yum –y install mariadb-server mariadb-devel systemctl start mariad…

    Linux干货 2016-12-21
  • N21-第五周

    1、显示/boot/grub/grub.conf中以至少一个空白字符开头的行; # grep "^[[:space:]]\+" /etc/grub.conf 2、显示/etc/rc.d/rc.sysinit文件中以#开头,后面跟至少一个空白字符,而后又有至少一个非空白字符的行; # grep&nbs…

    Linux干货 2016-08-15

评论列表(1条)

  • 马哥教育
    马哥教育 2016-12-07 23:48

    bash 相关的知识总结的很好,如能附加一些特殊变量的说明就更全面了