Bash Shell的语法知识

一、bash 简介

    为什么要学习 bash 编程呢?因为 bash 是每个 Linux 发行版都带有的一个标准基础软件,所以学会在 bash 下编制一些小程序就可以让你对 Linux 系统的管理应付自如;其次 bash 非常简单,比起C语言,Java这些,bash还是要简单很多;最后即使你不打算用 bash 编程,但是 Linux 系统中的许多配置文件和脚本都是 bash 的语法,不懂一点 bash 的知识就不能很好的理解和使用 Linux 。其实最简单的 bash 就和 DOS 下的批处理文件类似,只要把要执行的命令一行一行写出来就行。


二、bash的特点

    Bourne Again shell (bash), 正如它的名字所暗示的,是 Bourne shell 的扩展。BASH 与 Bourne shell 完全向后兼容,并且在 Bourne shell 的基础上增加和增强了很多特性。BASH 也包含了很多 csh 和 Korn Shell 里的优点,使得BASH 有很灵活和强大的编程接口,同时又有很友好的用户界面。为什么要用BASH 来代替 sh 呢?Bourne Shell 最大的缺点在于它处理用户的输入方面,在Bourne shell 里键入命令会很麻烦,尤其当你键入很多相似的命令时,而 BASH准备了几种特性使命令的输入变得更容易。 BASH 的新功能包括 命令补齐、通配符、命令历史记录、别名等。

    BASH 是一种解释执行的语言,我们还见过其他一些解释性的语言,如 BASIC 语言、Perl 语言、TCL/TL 等等。解释执行的语言的与编译型语言(如 C 语言)的最大不同就在于运行速度和使用方便程度上。BASH 和后面我们要讲解的 Perl语言都是解释性语言,他们编写起来很方便,也很快捷,但是由于是解释执行,所以运行速度和效率必将大打折扣。故而今天介绍的 BASH 和 Perl 这两种解释性语言最好的用途就是一些用于完成特定功能的常用的小工具或小程序,对于一些大型的项目、计算复杂的工程或有高级需求的应用还是用 C 语言甚至汇编语言比较好。


    下面给出一些 BASH所不适用的范围:

        资源型敏感,对 CPU 负担重的程序

        复杂的大项目

        需要灵活处理文件的程序,BASH 只能逐行读出文件进行处理

        需要图形用户界面的程序

        需要直接与系统硬件打交道的程序 

        要访问 I/O 端口和网络套接字的程序

        需要使用库或和以前的其他代码整合的程序


三、BASH 的基本语法

    1、最简单的例子 —— Hello World!

        #!/bin/bash 
        # This is a very simple example 
        echo Hello World

        第一行:#/bin/bash(shebang),在 BASH 中 第一行的 "#!" 及后面的 "/bin/bash" 就表明该文件是一个 BASH 程序,需要由 /bin 目录下的 bash 程序来解释执行。

        第二行:就是 BASH 程序的注释,在 BASH 程序中从“#”号(注意:后面紧接着是“!”号的除外)开始到行尾的多有部分均被看作是程序的注释。

        第三行:echo 语句的功能是把 echo 后面的字符串输出到标准输出中去。由于 echo 后跟的是 "Hello World" 这个字符串,因此 "Hello World"这个字串就被显示在控制台终端的屏幕上了。

        需要注意的是 BASH 中的绝大多数语句结尾处都没有分号。


    2、运行脚本的两种方式

        (1)、显式制定 BASH 去执行:

            bash hello.sh

        (2)、让它成为可执行文件后运行:

            chmod +x hello.sh
            ./hello.sh



        3、bash的变量类型      

            本地变量:作用域为当前shell进程

                varname=value

            环境变量:作用域只对当前代码段有效

                export varname=value

            局部变量:作用域只对当前代码段有效

                local varname=value

            位置变量

                $1, ..., $n, ${10}

            特殊变量:

              $?:状态返回值

              $#: 传递给脚本参数的个数

              $@ | $*:引用传递给脚本的所有参数,但是它们两者还是有区别的

              $0:表示命令本身


        4、bash的算术运算

        实现算术运算的方式:

            let VAR_NAME=ARITHMATIC_EXPRESSION(算术表达式)
                也是表达式,但是不可以直接引用,必须要赋值给变量之后才可以
            VAR_NAME=$[ARITHMATIC_EXRESSION](个人常用)
            VAR_NAME=$((EXPRESSION))
            VAR_NAME=$(expr $num1 + $num2)
                必须加空格,不然会语法错误

        算术运算符:

            +
            -
            *
            /
            %:取模,取余数
            **: 2**2 两个*号取多少次方


        5、bash的赋值

            赋值:

                a=4

            增强型赋值:

                +=, -=, *=, /=, %=



        6、bash的条件测试

            语法         

            test EXPR

            [ EXPR ]

            ` EXPR `


            整型测试:

        -gt: 大于
            例如 [ $num1 -gt $num2 ]
        -lt: 小于
        -ge: 大于等于
        -le: 小于等于 
        -eq: 等于
        -ne: 不等于



            字符串测试:

        双目
            >  大于
                [[ "$str1" > "$str2" ]]
            <  小于
            >= 大于等于
            <= 小于等于
            == 等于
            != 不等于
        单目:
            -n String: 是否不空,不空则为真,空则为假
            -z String: 是否为空,空则为真,不空则假



            文件测试:

        -a FILE
        -e FILE: 存在则为真;否则则为假;
        -f FILE: 存在并且为普通文件,则为真;否则为假;
        -d FILE: 存在并且为目录文件,则为真;否则为假;
        -L/-h FILE: 存在并且为符号链接文件,则为真;否则为假;
        -b: 块设备
        -c: 字符设备
        -S: 套接字文件
        -p: 命名管道
        -s FILE: 存在并且为非空文件则为值,否则为假;
        -r FILE:文件有读权限为真,否则为假
        -w FILE:文件有写权限为真,否则为假
        -x FILE:文件有执行权限为真,否则为假
        file1 -nt file2: file1的mtime新于file2则为真,否则为假;
        file1 -ot file2:file1的mtime旧于file2则为真,否则为假;

    

        7、bash的循环语句

       for语句
       格式1:
           for VAR_NAME in LIST
           do
               循环体
           done
         
       格式2:
           for VAR_NAME is LIST; do 循环体; done
              
       例子:创建10个用户,user301, user310           
           for userNo in $(seq 301 310); do
               useradd user${userNo}
           done
           
        for的第二种使用(c语言风格):
            for ((初始条件;测试条件;修改表达式)); do
                循环体
            one
         
         
         while格式:

	    while 测试条件; do
                循环体
            done

	    测试条件为真,进入循环;测试条件为假,退出循环;
            测试条件一般通过变量来描述,需要在循环体不变量地改变变量的值,以确保某一时刻测试条件为假,进而结束循环;

	  until格式:

            until 测试条件; do
                循环体
            done

            测试条件为假,进入循环;测试条件为真,退出循环;
            测试条件一般通过变量来描述,需要在循环体不变量地改变变量的值,以确保某一时刻测试条件为真,进而结束循环;

        

        8、bash的判断条件    

        if判断条件

        单分支的if语句:
            if 测试条件; then
             选择分支
            fi
            
        双分支的if语句:
            if 测试条件; then
                选择分支1
            else
                选择分支2
            fi
            
        多分支的if语句:
            if 条件1; then
                分支1
            elif 条件2; then
                分支2
            elif 条件3; then
                分支3
             ...
            else
                分支n
            fi


            case语句:有多个测试条件时,case语句会使得语法结构更明晰

            

        case 变量引用 in
        PATTERN1)
            分支1
            ;;
        PATTERN2)
            分支2
            ;;
        ...
        *)
            分支n
            ;;
        esac
        
        PATTERN:类同于文件名通配机制,但支持使用|表示或者;
            a|b: a或者b
            *:匹配任意长度的任意字符
            ?: 匹配任意单个字符
        []: 指定范围内的任意单个字符
        
        例如:用户键入字符后判断其所属的类别;
        #!/bin/bash
        #
        read -p "Plz enter a char: " char
        case $char in
        [0-9])
            echo "a digit"
            ;;
        [a-z])
            echo "a char"
            ;;
        *)
            echo "a special word"
            ;;
        esac


    9、bash编程函数

        函数就是模块化,代码重用

        语法:

            function F_NAME {

                函数体

            }


            F_NAME() {

                函数体

            }


            可调用:使用函数名

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


        bash脚本:默认整个脚本就是入口,没有要求必须做成函数化


        函数的返回值:

            函数的执行结果返回值:代码的输出

            函数中的打印语句:echo, print

            函数中调用的系统命令执行后返回的结果

        执行状态返回值:

            函数体中最后一次执行的命令状态结果

            自定函数执行状态的返回值:return #


        函数可以接受参数:

            在函数体中调用函数参数的方式同脚本中调用脚本参数的方式:位置参数

            $1, $2, ...

            $#, $*, $@



        示例:服务脚本示例

        #!/bin/bash
        #
        # chkconfig: 2345 67 34
        #
        srvName=$(basename $0)
        lockFile=/var/lock/subsys/$srvName
        
        start() {
            if [ -f $lockFile ];then
                echo "$srvName is already running."
                return 1
            else
                touch $lockFile
                [ $? -eq 0 ] && echo "Starting $srvName OK."
                return 0
             fi
         }
         
        stop() {
            if [ -f $lockFile ];then
                rm -f $lockFile &> /dev/null
                [ $? -eq 0 ] && echo "Stop $srvName OK" && return 0 
            else
                echo "$srvName is not started."
                return 1
            fi
        }
        
        status() {
            if [ -f $lockFile ]; then
                echo "$srvName is running."
            else
                echo "$srvName is stopped."
            fi
            return 0
        }
        
        usage() {
             echo "Usage: $srvName {start|stop|restart|status}"
             return 0
        }
        
        case $1 in
        start)
            start
            ;;
        stop)
            stop ;;
        restart)
            stop
            start ;;
        status)
            status ;;
        *)
            usage
            exit 1 ;;
        esac



这些就是bash的基本语法知识啦!!!


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章