系統管理中 bash shell 腳本常用方法總結

系統管理中 bash shell 腳本常用方法總結

在日常系統管理工作中,需要編寫腳本來完成特定的功能,編寫shell腳本是一個基本功了!在編寫的過程中,掌握一些常用的技巧和語法就可以完成大部分功能了,也就是2/8原則.

1. 單引號和雙引號的區別

單引號與雙引號的最大不同在於雙引號仍然可以引用變數的內容,但單引號內僅是 普通字元 ,不會作變數的引用,直接輸出字元竄。請看如下例子:

[root@linux ~]# name=HaHa[root@linux ~]# echo $nameHaHa[root@linux ~]# myname="$name is wow"[root@linux ~]# echo $mynameHaHa is wow[root@linux ~]# myname="$name is wow"[root@linux ~]# echo $myname$name is wow

從上面例子可以看出,使用了單引號的時候,那麼$name只是普通字元,直接輸出而已!

2. 逐行讀取文件

  • 使用for循環來讀取文件

    for line in `cat file.txt` do echo $line done

  • 注意:由於使用for來讀入文件里的行時,會自動把空格和換行符作為一樣分隔符,如果行里有空格的時候,輸出的結果會很亂,所以只適用於行連續不能有空格或者換行符的文件

  • 使用while循環讀取文件

    cat file.txt |while read line do echo $line done 或者: while read line do echo $line done < file.txt

  • 注意:由於使用while來讀入文件里的行時,會整行讀入,不會關注行的內容(空格..),所以比for讀文件有更好的適用性,推薦使用while循環讀取文件

    3. bash shell 腳本中常用隱含變數

    $0 當前執行的腳本或者命令名稱
    $1-$9 代表參數的位置. 舉例 $1 代表第一個參數.
    $# 腳本調用的參數的個數
    $@ 所有參數的內容
    $* 所有參數的內容
    $$ 當前運行腳本的進程號
    $? 命令執行後返回的狀態
    $! 後台運行的最後一個進程號

    注意: $? 用於檢查上一個命令執行是否正確(在Linux中,命令退出狀態為0表示該命令正確執行,任何非0值表示命令出錯)$$ 變數最常見的用途是用做暫存文件的名字以保證暫存文件不會重複。$* 和 $@ 如果輸出是一樣的,但是在使用for循環,在使用 雙引號(」")引用時 「$*」 會輸出成一個元素 而 「$@」 會按照每個參數是一個元素方式輸出

    請看測試例子

    #cat test.sh#!/bin/shecho ""$@" output....."for i in "$@"doecho $idoneecho ""$*" output ...."for i in "$*"doecho $idone

    輸出結果

    #sh test.sh a b c d"$@" output.....abcd"$*" output ....a b c d

    從輸出結果可以看出 「$*」 輸出是一行 而 「$@」 輸出則是四行

    4. 變數內容的刪除與替換

    我們在一些情況下,需要對變數中的字元竄進行查找刪除或者替換,就需要使用下表列出的方法

    變數設定方式 說明
    ${變數#關鍵字} 若變數內容從頭開始的資料符合『關鍵字』,則將符合的最短資料刪除
    ${變數##關鍵字} 若變數內容從頭開始的資料符合『關鍵字』,則將符合的最長資料刪除
    ${變數%關鍵字} 若變數內容從尾向前的資料符合『關鍵字』,則將符合的最短資料刪除
    ${變數%%關鍵字} 若變數內容從尾向前的資料符合『關鍵字』,則將符合的最長資料刪除
    ${變數/舊字串/新字串} 若變數內容符合『舊字串』則『第一個舊字串會被新字串取代
    ${變數//舊字串/新字串} 若變數內容符合『舊字串』則『全部的舊字串會被新字串取代

    舉例如下(刪除字元竄中的某個字元):

    [root@linux ~]# export test_str="/usr/kerberos/sbin:/usr/kerberos/bin:/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin:/root/bin"[root@linux ~]# echo ${test_str#/*kerberos/bin:}/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin:/root/bin

    5. 變數條件測試賦值

    在某些時刻我們需要『判斷』某個變數是否存在,若變數存在則將此變數值賦值給新的變數,若變數不存在則將其他值賦值給新的變數.

    變數設定方式 str 未定義 str 為空字串 str 已賦值為非空字串
    var=${str-expr} var=expr var= var=$str
    var=${str:-expr} var=expr var=expr var=$str
    var=${str+expr} var= var=expr var=expr
    var=${str:+expr} var= var= var=expr
    var=${str?expr} expr 輸出至 stderr var= var=$str
    var=${str:?expr} expr 輸出至 stderr expr 輸出至 stderr var=$str
    var=${str=expr} var=expr var= var=$str
    var=${str:=expr} var=expr var=expr var=$str

    舉例如下:

    [root@linux ~]# test_name=""[root@linux ~]# test_name=${test_name-root}[root@linux ~]# echo $test_name<== 因為 test_name 被設定為空字元竄!所以當然還是保留為空字元竄![root@linux ~]# test_name=${test_name:-root}[root@linux ~]# echo $test_nameroot <== 加上『:』後若變數內容為空或者是未設定,都能夠以後面的內容替換!

    基本上這種變數的測試也能夠透過 shell script 內的 if…then… 來處理,不過通過上述提及的簡單的方法來測試變數,是程序看起來更精簡一些!

    6. shell 中分隔符 : 變數IFS 使用

    shell腳本中,如果使用for循環一個字元竄的話,默認使用空格來分割字元竄. 還有前面所提到的使用for循環逐行讀取文件內容時候,文件行中如果有空格的話輸出的結果也會變亂. 這個時候 使用 IFS 變數來設置特定的字元竄分割符來,達到輸出正確的目的. 默認情況下 IFS 是使用 <space><tab><newline>, 空格 "t "n 來作為默認的分割符的.

    我們將前面使用for逐行讀取文件的例子 改進下就可以輸出正確了,請看下面

    #!/bin/bashIFS_old=$IFS #將原IFS值保存,以便用完後恢復IFS=$』"n』 #更改IFS值為$』"n』for line in `cat file.txt`doecho $linedone

    file.txt 文件內容如下

    [root@linux]$ cat file.txtsdfsdfsdfsdfssssss ssssss ssssss ssssssdfsdfsdfsdfsdf

    執行測試程序 輸出結果如下(正確輸出)

    [root@linux]$ sh test.shsdfsdfsdfsdfssssss ssssss ssssss ssssssdfsdfsdfsdfsdf

    如果未設置IFS變數,使用默認的IFS變數值 ,輸出結果如下

    [root@linux]$ sh test.shsdfsdfsdfsdfssssssssssssssssssssssssdfsdfsdfsdfsdf

    從以上測試程序輸出結果,可以根據自己的需求來設定 IFS變數,在舉一個例子如下:

    while IFS=: read userName passWord userID groupID geCos homeDir userShelldoecho "$userName -> $homeDir"done < /etc/passwd

    7. shell 數組的使用

    數組賦值方式:

    (1) array=(var1 var2 var3 ... varN)(2) array=([0]=var1 [1]=var2 [2]=var3 ... [n]=varN)(3) array[0]=var1arrya[1]=var2...array[n]=varN

    計算數組元素個數或者長度:

    (1) ${#array[@]}(2) ${#array[*]}

    了解了數組基礎語法,舉例說明,請看:

    #!/bin/bashNAMESERVERS=("ns1.www.net." "ns2.www.net." "ns3.www.net.")# 得到數組長度tLen=${#NAMESERVERS[@]}# 循環數組for (( i=0; i<${tLen}; i++ ));doecho ${NAMESERVERS[$i]}done

    在看一個複雜一點的例子,將文件內容讀取到數組中:

    #!/bin/bash# 設置IFS將分割符 設置為 換行符("n)OLDIFS=$IFSIFS=$""n" # 讀取文件內容到數組fileArray=($(cat file.txt))# restore itIFS=$OLDIFStLen=${#fileArray[@]}# 循環顯示文件內容for (( i=0; i<${tLen}; i++ ));doecho "${fileArray[$i]}"done

    8. 邏輯判斷 條件測試

  • 文件屬性的判斷
  • 操作符 測試結果
    -e filename 文件存在返回1, 否則返回0
    -r filename 文件可讀返回1,否則返回0
    -w filename 文件可寫返回1,否則返回0
    -x filename 文件可執行返回1,否則返回0
    -o filename 文件屬於用戶本人返回1, 否則返回0
    -z filename 文件長度為0返回1, 否則返回0
    -f filename 文件為普通文件返回1, 否則返回0
    -d filename 文件為目錄文件時返回1, 否則返回0

    舉例如下,測試文件是否存在:

    #!/bin/bashecho "checks the existence of the messages file."echo -n "Checking..."if [ -f /var/log/messages ];thenecho "/var/log/messages exists."fiechoecho "...done."

  • 字元串比較
  • 操作符 比較結果
    str1 = str2 當兩個字串相等時為真
    str1 != str2 當兩個字串不等時為真
    -n str1 當字元串的長度大於0時為真
    -z str1 當字元串的長度為0時為真
    str 當字元串為非空時為真

    舉例如下,比較字元串來測試用戶ID :

    if [ "$(whoami)" != "root" ]; thenecho "You have no permission to run $0 as non-root user."exit 1;fi

  • 數值比較(整數)
  • 操作符 比較結果
    num1 -eq num2 兩數相等為真
    num1 -ne num2 兩數不等為真
    num1 -gt num2 num1大於num2為真
    num1 -ge num2 num1大於等於num2為真
    num1 -lt num2 num1小於num2為真
    num1 -le num2 num1小於等於num2為真

    舉例如下:

    num=`wc -l work.txt`if [ $num -gt 150 ];thenecho "you"ve worked hard enough for today."echofi

    如果要查看詳細的測試操作,可以查看man手冊 man test


    推薦閱讀:

    天校2.0正式發布 更方便的系統管理工具
    使用 Ansible 讓你的系統管理自動化
    Ansible:像系統管理員一樣思考的自動化框架
    Ansible 教程:簡單 Ansible 命令介紹

    TAG:管理 | 腳本 | 方法 | 系統管理 | 系統 | 總結 |