Linux Shell常用技巧(十二) Shell編程

Linux Shell常用技巧(十二) Shell編程

二十三. Bash Shell編程:

    1.  讀取用戶變量:
    read命令是用於從終端或者文件中讀取輸入的內建命令,read命令讀取整行輸入,每行末尾的換行符不被讀入。在read命令後面,如果沒有指定變量名,讀取的數據將被自動賦值給特定的變量REPLY。下面的列表給出了read命令的常用方式:

命令格式描述
read answer從標準輸入讀取輸入並賦值給變量answer。
read first last從標準輸入讀取輸入到第一個空格或者回車,將輸入的第一個單詞放到變量first中,並將該行其他的輸入放在變量last中。
read從標準輸入讀取一行並賦值給特定變量REPLY。
read -a arrayname把單詞清單讀入arrayname的數組裏。
read -p prompt打印提示,等待輸入,並將輸入存儲在REPLY中。
read -r line允許輸入包含反斜槓。


    見下面的示例(綠色高亮部分的文本爲控制檯手工輸入信息):
    /> read answer        #等待讀取輸入,直到回車後表示輸入完畢,並將輸入賦值給變量answer
    Hello                       #控制檯輸入Hello
    /> echo $answer      #打印變量
    Hello

    #等待一組輸入,每個單詞之間使用空格隔開,直到回車結束,並分別將單詞依次賦值給這三個讀入變量。
    /> read one two three
    1 2 3                      #在控制檯輸入1 2 3,它們之間用空格隔開。
    /> echo "one = $one, two = $two, three = $three"
    one = 1, two = 2, three = 3

    /> read                  #等待控制檯輸入,並將結果賦值給特定內置變量REPLY。
    This is REPLY          #在控制檯輸入該行。
    /> echo $REPLY      #打印輸出特定內置變量REPLY,以確認是否被正確賦值。
    This is REPLY

    /> read -p "Enter your name: "    #輸出"Enter your name: "文本提示,同時等待輸入,並將結果賦值給REPLY。
    Enter you name: stephen            #在提示文本之後輸入stephen
    /> echo $REPLY
    stephen

    #等待控制檯輸入,並將輸入信息視爲數組,賦值給數組變量friends,輸入信息用空格隔開數組的每個元素
    /> read -a friends
    Tim Tom Helen
    /> echo "I have ${#friends} friends"
    I have 3 friends
    /> echo "They are ${friends[0]}, ${friends[1]} and ${friends[2]}."
    They are Tim, Tom and Helen.

   2.  狀態判斷:
    test是Shell中提供的內置命令,主要用於狀態的檢驗,如果結果爲0,表示成功,否則表示失敗。見如下示例:
    /> name=stephen
    /> test $name != stephen
    /> echo $?
    1
    需要注意的是test命令不支持Shell中提供的各種通配符,如:
    /> test $name = [Ss]tephen
    /> echo $?
    1
    test命令還可以中括號予以替換,其語義保持不變,如:
    /> [ $name = stephen ]
    /> echo $?
    0   
    在Shell中還提供了另外一種用於狀態判斷的方式:` expr `,和test不同的是,該方式中的表達式支持通配符,如:
    /> name=stephen
    /> [[ $name == [Ss]tephen ]]
    /> echo $?
    0
    #在` expression `中,expression可以包含&&(邏輯與)和||(邏輯或)。
    /> [[ $name == [Ss]tephen && $friend == "Jose" ]]
    /> echo $?
    1
    /> shopt -s extglob   #打開Shell的擴展匹配模式。
    /> name=Tommy
    # "[Tt]o+(m)y"的含義爲,以T或t開頭,後面跟着一個o,再跟着一個或者多個m,最後以一個y結尾。
    /> [[ $name == [Tt]o+(m)y ]]
    /> echo $?
    0
    在Shell中還提供了let命令的判斷方式: (( expr )),該方式的expr部分,和C語言提供的表達式規則一致,如:
    /> x=2
    /> y=3
    /> (( x > 2 ))
    /> echo $?
    1
    /> (( x < 2 ))
    /> echo $?
    0  
    /> (( x == 2 && y == 3 ))
    /> echo $?
    0
    /> (( x > 2 || y < 3 ))
    /> echo $?
    1

    下面的表格是test命令支持的操作符:

判斷操作符判斷爲真的條件
字符串判斷
[ stringA=stringB ]stringA等於stringB
[ stringA==stringB ]stringA等於stringB
[ stringA!=stringB ]stringA不等於stringB
[ string ]string不爲空
[ -z string ]string長度爲0
[ -n string ]string長度不爲0
邏輯判斷
[ stringA -a stringB ]stringA和stringB都是真
[ stringA -o stringB ]stringA或stringB是真
[ !string ]string不爲真
邏輯判斷(複合判斷)
[[ pattern1 && pattern2 ]]pattern1和pattern2都是真
[[ pattern1 || pattern2 ]pattern1或pattern2是真
[[ !pattern ]]pattern不爲真
整數判斷
[ intA -eq intB ]intA等於intB
[ intA -ne intB ]intA不等於intB
[ intA -gt intB ]intA大於intB
[ intA -ge intB ]intA大於等於intB
[ intA -lt intB ]intA小於intB
[ intA -le intB ]intA小於等於intB
文件判斷中的二進制操作
[ fileA -nt fileB ]fileA比fileB新
[ fileA -ot fileB ]fileA比fileB舊
[ fileA -ef fileB ]fileA和fileB有相同的設備或者inode值
文件檢驗
[ -d $file ] or [[ -d $file ]]file爲目錄且存在時爲真
[ -e $file ] or [[ -e $file ]]file爲文件且存在時爲真
[ -f $file ] or [[ -f $file ]]file爲非目錄普通文件存在時爲真
[ -s $file ] or [[ -s $file ]]file文件存在, 且長度不爲0時爲真
[ -L $file ] or [[ -L $file ]]file爲鏈接符且存在時爲真
[ -r $file ] or [[ -r $file ]]file文件存在且可讀時爲真
[ -w $file ] or [[ -w $file ]]file文件存在且可寫時爲真
[ -x $file ] or [[ -x $file ]]file文件存在且可執行時爲真

    注:在邏輯判斷(複合判讀中),pattern可以包含元字符,在字符串的判斷中,pattern2必須被包含在引號中。

    let命令支持的操作符和C語言中支持的操作符完全相同,如:
    +,-,*,/,%            加,減,乘,除,去模
    >>,<<                右移和左移
    >=,<=,==,!=      大於等於,小於等於,等於,不等於
    &,|,^                  按位與,或,非
    &&,||,!                邏輯與,邏輯或和取反
    還有其含義和C語言等同的快捷操作符,如=,*=,/=,%=,+=,-=,<<=,>>=,&=,|=,^=。

    3.  流程控制語句:
    if語句格式如下:
    #if語句的後面是Shell命令,如果該命令執行成功返回0,則執行then後面的命令。
    if command        
    then
        command
        command
    fi
    #用test命令測試其後面expression的結果,如果爲真,則執行then後面的命令。
    if test expression
    then
        command
    fi
    #下面的格式和test expression等同
    if [ string/numeric expression ]
    then
        command
    fi
    #下面的兩種格式也可以用於判斷語句的條件表達式,而且它們也是目前比較常用的兩種。
    if ` string expression `
    then
        command
    fi

    if (( numeric expression ))           #let表達式
    then
        command
    fi
    見如下示例:
    /> cat > test1.sh                       #從命令行直接編輯test1.sh文件。
    echo -e "Are you OK(y/n)? \c"
    read answer
    #這裏的$answer變量必須要用雙引號擴住,否則判斷將失敗。當變量$answer等於y或Y時,支持下面的echo命令。
    if [ "$answer" = y -o "$answer" = Y ]   
    then
        echo "Glad to see it."
    fi
    CTRL+D  
    /> . ./test1.sh
    Are you OK(y/n)? y
    Glad to see it.
    上面的判斷還可以替換爲:
    /> cat > test2.sh
    echo -e "Are you OK(y/n or Maybe)? \c"
    read answer
    # ` `複合命令操作符允許其中的表達式包含元字符,這裏輸入以y或Y開頭的任意單詞,或Maybe都執行then後面的echo。
    if [[ $answer == [yY]* || $answer = Maybe ]]  
    then
        echo "Glad to hear it.
    fi
    CTRL+D
    /> . ./test2.sh
    Are you OK(y/n or Maybe)? yes
    Glad to hear it.
    下面的例子將使用Shell中的擴展通配模式。
    /> shopt -s extglob        #打開該擴展模式
    /> answer="not really"
    /> if [[ $answer = [Nn]o?( way |t really) ]]
    > then
    >    echo "I am sorry."
    > fi
    I am sorry.
    對 於本示例中的擴展通配符,這裏需要給出一個具體的解釋。[Nn]o匹配No或no,?( way|t really)則表示0個或1個( way或t   really),因此answer變量匹配的字符串爲No、no、Not really、not really、No way、no way。
    下面的示例使用了let命令操作符,如:
    /> cat > test3.sh
    if (( $# != 2 ))                    #等同於 [ $# -ne 2 ]
    then
        echo "Usage: $0 arg1 arg2" 1>&2
        exit 1                         #exit退出值爲0-255之間,只有0表示成功。
    fi
    if (( $1 < 0 || $1 > 30 ))      #等同於 [ $1 -lt 0 -o $1 -gt 30 ]
    then
        echo "arg1 is out of range."
        exit 2
    fi
    if (( $2 <= 20 ))                  #等同於 [ $2 -le 20 ]
    then
        echo "arg2 is out of range."
    fi
    CTRL+D
    /> sh ./test3.sh
    Usage: ./test3.sh arg1 arg2
    /> echo $?                          #Shell腳本的退出值爲exit的參數值。
    1
    /> sh ./test3.sh 40 30
    arg1 is out of range.
    /> echo $?
    2
    下面的示例爲如何在if的條件表達式中檢驗空變量:
    /> cat > test4.sh
    if [ "$name" = "" ]                #雙引號就表示空字符串。
    then
        echo "name is null."
    fi
    CTRL+D
    /> . ./test4.sh
    name is null.

    if/elif/else語句的使用方式和if語句極爲相似,相信有編程經驗的人都不會陌生,這裏就不再贅述了,其格式如下:
    if command
    then
        command
    elif command
    then
        command
    else
        command
    fi
    見如下示例腳本:
    /> cat > test5.sh
    echo -e "How old are you? \c"
    read age
    if [ $age -lt 0 -o $age -gt 120 ]                #等同於 (( age < 0 || age > 120 ))
    then
        echo "You are so old."
    elif [ $age -ge 0 -a $age -le 12 ]               #等同於 (( age >= 0 && age <= 12 ))
    then
        echo "You are child."
    elif [ $age -ge 13 -a $age -le 19 ]             #等同於 (( age >= 13 && age <= 19 ))
    then
        echo "You are 13--19 years old."
    elif [ $age -ge 20 -a $age -le 29 ]             #等同於 (( age >= 20 && age <= 29 ))
    then
        echo "You are 20--29 years old."
    elif [ $age -ge 30 -a $age -le 39 ]             #等同於 (( age >= 30 && age <= 39 ))
    then
        echo "You are 30--39 years old."
    else
        echo "You are above 40."
    fi
    CTRL+D
    /> . ./test5.sh
    How old are you? 50
    You are above 40.

    case語句格式如下:
    case variable in
    value1)
        command
        ;;            #相同於C語言中case語句內的break。
    value2)
        command
        ;;
    *)                #相同於C語言中switch語句內的default
       command
        ;;
    esac
    見如下示例腳本:
    /> cat > test6.sh
    #!/bin/sh
    echo -n "Choose a color: "
    read color
    case "$color" in
    [Bb]l??)
        echo "you select blue color."
        ;;
    [Gg]ree*)
        echo "you select green color."
        ;;
    red|orange)
        echo "you select red or orange."
        ;;
    *)
        echo "you select other color."
        ;;
    esac
    echo "Out of case command."
    /> . ./test6.sh
    Choose a color: green
    you select green color.
    Out of case command.

   4.  循環語句:
    Bash Shell中主要提供了三種循環方式:for、while和until
    for循環聲明格式:
    for variable in word_list
    do
        command
    done
    見如下示例腳本:
    /> cat > test7.sh
    for score in math english physics chemist   #for將循環讀取in後面的單詞列表,類似於Java的for-each。
    do
        echo "score = $score"
    done
    echo "out of for loop"
    CTRL+D
    /> . ./test7.sh
    score = math
    score = english
    score = physics
    score = chemist
    out of for loop

    /> cat > mylist   #構造數據文件
    tom
    patty
    ann
    jake
    CTRL+D
    /> cat > test8.sh
    #!/bin/sh
    for person in $(cat mylist)                 #for將循環讀取cat mylist命令的執行結果。
    do
        echo "person = $person"
    done
    echo "out of for loop."
    CTRL+D
    /> . ./test8.sh
    person = tom
    person = patty
    person = ann
    person = jake
    out of for loop.

    /> cat > test9.sh
    for file in test[1-8].sh                        #for將讀取test1-test8,後綴爲.sh的文件
    do
        if [ -f $file ]                              #判斷文件在當前目錄是否存在。
        then
            echo "$file exists."
        fi
    done
    CTRL+D
    /> . ./test9.sh
    test2.sh exists.
    test3.sh exists.
    test4.sh exists.
    test5.sh exists.
    test6.sh exists.
    test7.sh exists.
    test8.sh exists.

    /> cat > test10.sh
    for name in $*                                  #讀取腳本的命令行參數數組,還可以寫成for name的簡化形式。
    do
        echo "Hi, $name"
    done
    CTRL+D
    /> . ./test10.sh stephen ann
    Hi, stephen
    Hi, ann

    while循環聲明格式:
    while command  #如果command命令的執行結果爲0,或條件判斷爲真時,執行循環體內的命令。
    do
        command
    done
    見如下示例腳本:
    /> cat > test1.sh  
    num=0
    while (( num < 10 ))               #等同於 [ $num -lt 10 ]
    do
        echo -n "$num "
        let num+=1
    done
    echo -e "\nHere's out of loop."
    CTRL+D
    /> . ./test1.sh
    0 1 2 3 4 5 6 7 8 9
    Here's out of loop.

    /> cat > test2.sh
    go=start
    echo Type q to quit.
    while [[ -n $go ]]                     #等同於[ -n "$go" ],如使用該風格,$go需要被雙引號括起。
    do
        echo -n How are you.
        read word
        if [[ $word == [Qq] ]]      #等同於[ "$word" = Q -o "$word" = q ]
        then
            echo Bye.
            go=                        #將go變量的值置空。
        fi
    done
    CTRL+D
    /> . ./test2.sh
    How are you. Hi
    How are you. q
    Bye.

    until循環聲明格式:
    until command                         #其判斷條件和while正好相反,即command返回非0,或條件爲假時執行循環體內的命令。
    do
        command
    done
    見如下示例腳本:
    /> cat > test3.sh
    until who | grep stephen           #循環體內的命令將被執行,直到stephen登錄,即grep命令的返回值爲0時才退出循環。
    do
        sleep 1
        echo "Stephen still doesn't login."
    done
    CTRL+D

    shift命令聲明格式:shift [n]
    shift命令用來把腳本的位置參數列表向左移動指定的位數(n),如果shift沒有參數,則將參數列表向左移動一位。一旦移位發生,被移出列表的參數就被永遠刪除了。通常在while循環中,shift用來讀取列表中的參數變量。
    見如下示例腳本:
    /> set stephen ann sheryl mark #設置4個參數變量。
    /> shift                                    #向左移動參數列表一次,將stephen移出參數列表。
    /> echo $*
    ann sheryl mark
    /> shift 2                                 #繼續向左移動兩位,將sheryl和ann移出參數列表
    /> echo $*
    mark
    /> shift 2                                 #繼續向左移動兩位,由於參數列表中只有mark了,因此本次移動失敗。
    /> echo $*
    mark

    /> cat > test4.sh
    while (( $# > 0 ))                    #等同於 [ $# -gt 0 ]
    do
        echo $*
        shift
    done
    CTRL+D
    /> . ./test4.sh a b c d e
    a b c d e
    b c d e
    c d e
    d e
    e        

    break命令聲明格式:break [n]
    和C語言不同的是,Shell中break命令攜帶一個參數,即可以指定退出循環的層數。如果沒有指定,其行爲和C語言一樣,即退出最內層循環。如果指定循環的層數,則退出指定層數的循環體。如果有3層嵌套循環,其中最外層的爲1,中間的爲2,最裏面的是3。
    見如下示例腳本:
    /> cat > test5.sh
    while true
    do
        echo -n "Are you ready to move on?"
        read answer
        if [[ $answer == [Yy] ]]
        then
            break
        else
            echo "Come on."
        fi
    done
    echo "Here we are."
    CTRL+D
    /> . ./test5.sh
    Are you ready to move on? y
    Here we are

    continue命令聲明格式:continue [n]
      和C語言不同的是,Shell中continue命令攜帶一個參數,即可以跳轉到指定層級的循環頂部。如果沒有指定,其行爲和C語言一樣,即跳轉到最內 層循環的頂部。如果指定循環的層數,則跳轉到指定層級循環的頂部。如果有3層嵌套循環,其中最外層的爲3,中間的爲2,最裏面的是1。
    /> cat  maillist                       #測試數據文件maillist的內容爲以下信息。
    stephen
    ann
    sheryl
    mark

    /> cat > test6.sh
    for name in $(cat maillist)
    do
        if [[ $name == stephen ]]; then
            continue
        else
            echo "Hello, $name."
        fi
    done
    CTRL+D
    /> . ./test6.sh
    Hello, ann.
    Hello, sheryl.
    Hello, mark.

    I/O重新定向和子Shell:
    文件中的輸入可以通過管道重新定向給一個循環,輸出也可以通過管道重新定向給一個文件。Shell啓動一個子Shell來處理I/O重新定向和管道。在循環終止時,循環內部定義的任何變量對於腳本的其他部分來說都是不可見的。
    /> cat > demodata                        #爲下面的腳本構造測試數據
    abc
    def
    ghi
    CRTL+D
    /> cat > test7.sh
    if (( $# < 1 ))                                #如果腳本參數的數量小於1,則給出錯誤提示後退出。
    then
        echo "Usage: $0 filename " >&2
        exit 1
    fi
    count=1
    cat $1 | while read line                   #參數一中的文件被cat命令輸出後,通過管道逐行輸出給while read line。
    do
        let $((count == 1)) && echo "Processing file $1..." > /dev/tty  #該行的echo將輸出到當前終端窗口。
        echo -e "$count\t$line"              #將輸出行號和文件中該行的內容,中間用製表符隔開。
        let count+=1
    done > outfile                               #將while循環中所有的輸出,除了>/dev/tty之外,其它的全部輸出到outfile文件。
    CTRL+D
    /> . ./test7.sh demodata                #只有一行輸出,其餘的都輸出到outfile中了。
    Processing file demodata...
    /> cat outfile
    1       abc
    2       def
    3       ghi

    /> cat > test8.sh
    for i in 9 7 2 3 5 4
    do
        echo $i
    done | sort -n                                #直接將echo的輸出通過管道重定向sort命令。
    CTRL+D
    /> . ./test8.sh
    2
    3
    4
    5
    7
    9

    5.  IFS和循環:
      Shell的內部域分隔符可以是空格、製表符和換行符。它可以作爲命令的分隔符用在例如read、set和for等命令中。如果在列表中使用不同的分隔 符,用戶可以自己定義這個符號。在修改之前將IFS原始符號的值保存在另外一個變量中,這樣在需要的時候還可以還原。
    見如下示例腳本:
    /> cat > test9.sh
    names=Stephen:Ann:Sheryl:John   #names變量包含的值用冒號分隔。
    oldifs=$IFS                                   #保留原有IFS到oldifs變量,便於後面的還原。
    IFS=":"                            
    for friends in $names                     #這是遍歷以冒號分隔的names變量值。    
    do
        echo Hi $friends
    done
    IFS=$oldifs                                   #將IFS還原爲原有的值。
    set Jerry Tom Angela
    for classmates in $*                      #再以原有IFS的值變量參數列表。
    do
        echo Hello $classmates
    done
    CTRL+D
    /> . ./test9.sh
    Hi Stephen
    Hi Ann
    Hi Sheryl
    Hi John
    Hello Jerry
    Hello Tom
    Hello Angela

    6.  函數:
    Shell中函數的職能以及優勢和C語言或其它開發語言基本相同,只是語法格式上的一些差異。下面是Shell中使用函數的一些基本規則:
    1) 函數在使用前必須定義。
    2) 函數在當前環境下運行,它和調用它的腳本共享變量,並通過位置參量傳遞參數。而該位置參量將僅限於該函數,不會影響到腳本的其它地方。
    3) 通過local函數可以在函數內建立本地變量,該變量在出了函數的作用域之後將不在有效。
    4) 函數中調用exit,也將退出整個腳本。
    5) 函數中的return命令返回函數中最後一個命令的退出狀態或給定的參數值,該參數值的範圍是0-256之間。如果沒有return命令,函數將返回最後一個Shell的退出值。
    6) 如果函數保存在其它文件中,就必須通過source或dot命令把它們裝入當前腳本。
    7) 函數可以遞歸。
    8) 將函數從Shell中清空需要執行:unset -f function_name。
    9) 將函數輸出到子Shell需要執行:export -f function_name。
    10) 可以像捕捉Shell命令的返回值一樣獲取函數的返回值,如$(function_name)。
    Shell中函數的聲明格式如下:
    function function_name { command; command; }
    見如下示例腳本:
    /> cat > test1.sh
    function increment() {            #定義函數increment。
        local sum                           #定義本地變量sum。
        let "sum=$1+1"    
        return $sum                      #返回值是sum的值。
    }
    echo -n "The num is "
    increment 5                          #increment函數調用。
    echo $?                                #輸出increment函數的返回值。
    CTRL+D
    /> . ./test1.sh
    The num is 6

    7.  陷阱信號(trap):
      在Shell程序運行的時候,可能收到各種信號,有的來自於操作系統,有的來自於鍵盤,而該Shell在收到信號後就立刻終止運行。但是在有些時候,你 可能並不希望在信號到達時,程序就立刻停止運行並退出。而是他能希望忽略這個信號而一直在運行,或者在退出前作一些清除操作。trap命令就允許你控制你 的程序在收到信號以後的行爲。
    其格式如下:
    trap 'command; command' signal-number
    trap 'command; command' signal-name
    trap signal-number  
    trap signal-name
    後面的兩種形式主要用於信號復位,即恢復處理該信號的缺省行爲。還需要說明的是,如果trap後面的命令是使用單引號括起來的,那麼該命令只有在捕獲到指定信號時才被執行。如果是雙引號,則是在trap設置時就可以執行變量和命令替換了。
    下面是系統給出的信號數字和信號名稱的對照表:
    1)SIGHUP 2)SIGINT 3)SIGQUIT 4)SIGILL 5)SIGTRAP 6)SIGABRT 7)SIGBUS 8)SIGFPE
    9)SIGKILL 10) SIGUSR1 11)SIGEGV 12)SIGUSR2 13)SIGPIPE 14)SIGALRM 15)SIGTERM 17)SIGCHLD
    18)SIGCONT 19)SIGSTOP ... ...
    見如下示例腳本:
    /> trap 'rm tmp*;exit 1' 1 2 15      #該命令表示在收到信號1、2和15時,該腳本將先執行rm tmp*,然後exit 1退出腳本。
    /> trap 2                                      #當收到信號2時,將恢復爲以前的動作,即退出。
    /> trap " " 1 2                               #當收到信號1和2時,將忽略這兩個信號。
    /> trap -                                       #表示恢復所有信號處理的原始值。
    /> trap 'trap 2' 2                           #在第一次收到信號2時,執行trap 2,這時將信號2的處理恢復爲缺省模式。在收到信號2時,Shell程序退出。
    /> cat > test2.sh
    trap 'echo "Control+C will not terminate $0."' 2   #捕獲信號2,即在鍵盤上按CTRL+C。
    trap 'echo "Control+\ will not terminate $0."' 3   #捕獲信號3,即在鍵盤上按CTRL+\。
    echo "Enter stop to quit shell."
    while true                                                        #無限循環。
    do
        echo -n "Go Go...."
        read
        if [[ $REPLY == [Ss]top ]]                            #直到輸入stop或Stop才退出循環和腳本。
       then
            break
        fi
    done
    CTRL+D
    /> . ./test2.sh
    Enter stop to quit shell.
    Go Go....^CControl+C will not terminate -bash.
    ^\Control+\ will not terminate -bash.
    stop

    8.  用getopts處理命令行選項:
    這裏的getopts命令和C語言中的getopt幾乎是一致的,因爲腳本的位置參量在有些時候是失效的,如ls -lrt等。這時候-ltr都會被保存在$1中,而我們實際需要的則是三個展開的選項,即-l、-r和-t。見如下帶有getopts的示例腳本:
    /> cat > test3.sh
    #!/bin/sh
    while getopts xy options                           #x和y是合法的選項,並且將-x讀入到變量options中,讀入時會將x前面的橫線去掉。
    do
        case $options in
        x) echo "you entered -x as an option" ;;       
        y) echo "you entered -y as an option" ;;
        esac
    done
    /> ./test3.sh -xy
    you entered -x as an option
    you entered -y as an option
    /> ./test3.sh -x
    you entered -x as an option
    /> ./test3.sh -b                                       #如果輸入非法選項,getopts會把錯誤信息輸出到標準錯誤。
    ./test3.sh: illegal option -- b
    /> ./test3.sh b                                        #該命令不會有執行結果,因爲b的前面有沒橫線,因此是非法選項,將會導致getopts停止處理並退出。

    /> cat > test4.sh
    #!/bin/sh
    while getopts xy options 2>/dev/null         #如果再出現選項錯誤的情況,該重定向會將錯誤輸出到/dev/null。
    do
        case $options in
        x) echo "you entered -x as an option" ;;
        y) echo "you entered -y as an option" ;;
        \?) echo "Only -x and -y are valid options" 1>&2 # ?表示所有錯誤的選項,即非-x和-y的選項。
    esac
    done
    /> . ./test4.sh -g                                     #遇到錯誤的選項將直接執行\?)內的代碼。
    Only -x and -y are valid options
    /> . ./test4.sh -xg
    you entered -x as an option
    Only -x and -y are valid options

    /> cat > test5.sh
    #!/bin/sh
    while getopts xyz: arguments 2>/dev/null #z選項後面的冒號用於提示getopts,z選項後面必須有一個參數。
    do
        case $arguments in
        x) echo "you entered -x as an option." ;;
        y) echo "you entered -y as an option." ;;
        z) echo "you entered -z as an option."  #z的後面會緊跟一個參數,該參數保存在內置變量OPTARG中。
            echo "\$OPTARG is $OPTARG.";
           ;;
        \?) echo "Usage opts4 [-xy] [-z argument]"
            exit 1 ;;
        esac
    done
    echo "The number of arguments passed was $(( $OPTIND - 1 ))" #OPTIND保存一下將被處理的選項的位置,他是永遠比實際命令行參數多1的數。
    /> ./test5.sh -xyz foo
    you entered -x as an option.
    you entered -y as an option.
    you entered -z as an option.
    $OPTARG is foo.
    The number of arguments passed was 2
    /> ./test5.sh -x -y -z boo
    you entered -x as an option.
    you entered -y as an option.
    you entered -z as an option.
    $OPTARG is boo.
    The number of arguments passed was 4

    9.  eval命令與命令行解析:
    eval命令可以對命令行求值,做Shell替換,並執行命令行,通常在普通命令行解析不能滿足要求時使用。
    /> set a b c d
    /> echo The last argument is \$$#
    The last argument is $4
    /> eval echo The last argument is \$$#    #eval命令先進行了變量替換,之後再執行echo命令。
    The last argument is d


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