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.www58058.com/61364

(0)
N24_yeziN24_yezi
上一篇 2016-11-28
下一篇 2016-11-28

相關推薦

評論列表(1條)

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

    bash 相關的知識總結的很好,如能附加一些特殊變量的說明就更全面了

欧美性久久久久