Linux Bash指令碼15分鐘進階教程__Linux

來源:互聯網
上載者:User

這裡的技術技巧最初是來自Google的“Testing on the Toilet” (TOTT)。這裡是一個修訂和擴增版本。 指令碼安全

我的所有bash指令碼都以下面幾句為開場白:

    #!/bin/bash    set -o nounset    set -o errexit

這樣做會避免兩種常見的問題: 引用未定義的變數(預設值為“”) 執行失敗的命令被忽略

需要注意的是,有些Linux命令的某些參數可以強制忽略發生的錯誤,例如“mkdir -p” 和 “rm -f”。

還要注意的是,在“errexit”模式下,雖然能有效捕捉錯誤,但並不能捕捉全部失敗的命令,在某些情況下,一些失敗的命令是無法檢測到的。(更多細節請參考這個文章。) 指令碼函數

在bash裡你可以定義函數,它們就跟其它命令一樣,可以隨意的使用;它們能讓你的指令碼更具可讀性:

    ExtractBashComments() {        egrep "^#"    }     cat myscript.sh | ExtractBashComments | wc     comments=$(ExtractBashComments < myscript.sh)

還有一些例子:

    SumLines() {  # iterating over stdin - similar to awk              local sum=0        local line=””        while read line ; do            sum=$((${sum} + ${line}))        done        echo ${sum}    }     SumLines < data_one_number_per_line.txt     log() {  # classic logger       local prefix="[$(date +%Y/%m/%d\ %H:%M:%S)]: "       echo "${prefix} $@" >&2    }     log "INFO" "a message"

儘可能的把你的bash代碼移入到函數裡,僅把全域變數、常量和對“main”調用的語句放在最外層。 變數註解

Bash裡可以對變數進行有限的註解。最重要的兩個註解是: local(函數內部變數) readonly(唯讀變數)

    # a useful idiom: DEFAULT_VAL can be overwritten    #       with an environment variable of the same name    readonly DEFAULT_VAL=${DEFAULT_VAL:-7}     myfunc() {       # initialize a local variable with the global default       local some_var=${DEFAULT_VAL}       ...    }

這樣,你可以將一個以前不是唯讀變數的變數聲明成唯讀變數:

x=5x=6readonly xx=7   # failure

盡量對你bash指令碼裡的所有變數使用local或readonly進行註解。 用$()代替反單引號(`)

反單引號很難看,在有些字型裡跟正單引號很相似。$()能夠內嵌使用,而且避免了轉義符的麻煩。

# both commands below print out: A-B-C-Decho "A-`echo B-\`echo C-\\\`echo D\\\`\``"echo "A-$(echo B-$(echo C-$(echo D)))"
用[[]](雙層中括弧)替代[]

使用[[]]能避免像異常的副檔名之類的問題,而且能帶來很多文法上的改進,而且還增加了很多新功能:

操作符 功能說明
|| 邏輯or(僅雙中括弧裡使用)
&& 邏輯and(僅雙中括弧裡使用)
< 字串比較(雙中括弧裡不需要轉移)
-lt 數字比較
= 字串相等
== 以Globbing方式進行字串比較(僅雙中括弧裡使用,參考下文)
=~ 用Regex進行字串比較(僅雙中括弧裡使用,參考下文)
-n 非Null 字元串
-z Null 字元串
-eq 數字相等
-ne 數字不等

單中括弧:

[ "${name}" \> "a" -o ${name} \< "m" ]

雙中括弧

[[ "${name}" > "a" && "${name}" < "m"  ]]
Regex/Globbing

使用雙中括弧帶來的好處用下面幾個例子最能表現:

t="abc123"[[ "$t" == abc* ]]         # true (globbing比較)[[ "$t" == "abc*" ]]       # false (字面比較)[[ "$t" =~ [abc]+[123]+ ]] # true (Regex比較)[[ "$t" =~ "abc*" ]]       # false (字面比較)

注意,從bash 3.2版開始,Regex和globbing運算式都不能用引號包裹。如果你的運算式裡有空格,你可以把它儲存到一個變數裡:

r="a b+"[[ "a bbb" =~ $r ]]        # true

按Globbing方式的字串比較也可以用到case語句中:

case $t inabc*)  <action> ;;esac
字串操作

Bash裡有各種各樣操作字串的方式,很多都是不可取的。

基本使用者

    f="path1/path2/file.ext"      len="${#f}" # = 20 (字串長度)     # 切片操作: ${<var>:<start>} or ${<var>:<start>:<length>}    slice1="${f:6}" # = "path2/file.ext"    slice2="${f:6:5}" # = "path2"    slice3="${f: -8}" # = "file.ext"(注意:"-"前有空格)    pos=6    len=5    slice4="${f:${pos}:${len}}" # = "path2"

替換操作(使用globbing)

    f="path1/path2/file.ext"      single_subst="${f/path?/x}"   # = "x/path2/file.ext"    global_subst="${f//path?/x}"  # = "x/x/file.ext"     # 字串拆分    readonly DIR_SEP="/"    array=(${f//${DIR_SEP}/ })    second_dir="${arrray[1]}"     # = path2

刪除頭部或尾部(使用globbing)

    f="path1/path2/file.ext"     # 刪除字串頭部    extension="${f#*.}"  # = "ext"     # 以貪婪匹配方式刪除字串頭部    filename="${f##*/}"  # = "file.ext"     # 刪除字串尾部    dirname="${f%/*}"    # = "path1/path2"     # 以貪婪匹配方式刪除字串尾部    root="${f%%/*}"      # = "path1"
避免使用臨時檔案

有些命令需要以檔案名稱為參數,這樣一來就不能使用管道。這個時候 <() 就顯出用處了,它可以接受一個命令,並把它轉換成可以當成檔案名稱之類的什麼東西:

# 下載並比較兩個網頁diff <(wget -O - url1) <(wget -O - url2)

還有一個非常有用處的是”here documents”,它能讓你在標準輸入上輸入多行字串。下面的’MARKER’可以替換成任何字詞。

# 任何字詞都可以當作分界符command  << MARKER...${var}$(cmd)...MARKER

如果文本裡沒有內嵌變數替換操作,你可以把第一個MARKER用單引號包起來:

command << 'MARKER'...no substitution is happening here.$ (dollar sign) is passed through verbatim....MARKER
內建變數
變數 說明
$0 指令碼名稱
$n 傳給指令碼/函數的第n個參數
$$ 指令碼的PID
$! 上一個被執行的命令的PID(後台啟動並執行進程)
$? 上一個命令的退出狀態(管道命令使用${PIPESTATUS})
$# 傳遞給指令碼/函數的參數個數
$@ 傳遞給指令碼/函數的所有參數(識別每個參數)
$* 傳遞給指令碼/函數的所有參數(把所有參數當成一個字串)
提示 使用 $*很少是正確的選擇。 $@能夠處理空格參數,而且參數間的空格也能正確的處理。 使用 $@時應該用雙引號括起來,像”$@”這樣。 調試

對指令碼進行語法檢查:

bash -n myscript.sh

跟蹤指令碼裡每個命令的執行:

bash -v myscripts.sh

跟蹤指令碼裡每個命令的執行並附加擴充資訊:

bash -x myscript.sh

你可以在指令碼頭部使用set -o verbose和set -o xtrace來永久指定-v和-o。當在遠程機器上執行指令碼時,這樣做非常有用,用它來輸出遠程資訊。 什麼時候不應該使用bash指令碼 你的指令碼太長,多達幾百行 你需要比數組更複雜的資料結構 出現了複雜的轉義問題 有太多的字串操作 不太需要調用其它程式和跟其它程式管道互動 擔心效能

這個時候,你應該考慮一種指令碼語言,比如Python或Ruby。 參考 Advanced Bash-Scripting Guide: http://tldp.org/LDP/abs/html/ Bash Reference Manual

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.