Linux系統學習筆記:BASH編程 使用 var=(element element ...) 建立陣列變數。引用數組中的元素時使用 ${var[i]} , i 為下標,下標@ 複製原數組,下標 * 也複製原數組,但加雙引號時它將原數組作為一個元素。給數組中單個元素賦值時可以用 var[i]=value 。 ${#var[i]} 返回元素的長度, ${#var[*]} 返回數組中元素的個數。 $ array=(Alex Harry Nancy)$ arr1=("${array[@]}")$ arr2=("${array[*]}")$ declare -adeclare -a arr1='([0]="Alex" [1]="Harry" [2]="Nancy")'declare -a arr2='([0]="Alex Harry Nancy")'declare -a array='([0]="Alex" [1]="Harry" [2]="Nancy")'$ array[1]=Jerry$ echo ${array[*]}Alex Jerry Nancy$ echo ${array[@]}Alex Jerry Nancy$ echo ${#array[*]} ${#array[1]}3 5變數的範圍為當前指令碼,可以用 export 聲明變數,它將父進程的變數變為對子進程是可用的。函數中的變數預設不是局部的,範圍也為當前指令碼,為了避免衝突,可以用 typeset 將它聲明為局部變數。 ${#var} 返回變數的長度。 ${var:-default} 使用變數的值,如果值為空白或未賦值,則使用給出的預設值。 ${var:=default} 和前者類似,但它同時會在值為空白或未賦值時將預設值賦給變數。 ${var:?message} 可以在值為空白或未賦值時顯示錯誤資訊,如果未給出 message ,則顯示預設錯誤資訊。 $ cd ${dir:?$(date +%T) error, dir not set.}-bash: dir: 10:15:29 error, dir not set.: 可以給其後的變數賦值但不去執行它,常常用 : ${var:=default} 來給變數設定預設值。 BASH中有一種字串模式比對,形式為 ${varOPpattern} , OP 為: # 去除最小匹配首碼, ## 去除最大匹配首碼, % 去除最小匹配尾碼, %% 去除最大匹配尾碼。 $ file=/home/yeolar/a.sh$ echo ${file##/*/}a.sh$ echo ${file%/*}/home/yeolar((var=base#n)) 文法可以給變數以其他基數賦值。 $ ((n=8#0101)); echo $n65位置參數位置參數儲存命令和命令後的參數。可以用 set 改變位置參數的內容,但不能在指令碼內改變命令名。 $# 儲存參數的個數, $0 儲存命令名, $1 - $n 儲存命令後的參數, $@ 和 $* 儲存全部參數,和陣列變數類似,加雙引號時 $* 作為一個參數,而 $@ 作為一組參數。 shift 左移參數。 set 初始化參數( set 沒有參數時顯示已設定的shell變數,還可以用它來設定shell特性)。 $ cat a.shecho "cmd: $0, args: $*, argnum: $#"echo "first arg: $1"echo "shift args..."shiftecho "cmd: $0, args: $*, argnum: $#"echo "first arg: $1"set "$@"echo "first arg: $1"set "$*"echo "first arg: $1"set a b cecho $*$ bash a.sh x y zcmd: a.sh, args: x y z, argnum: 3first arg: xshift args...cmd: a.sh, args: y z, argnum: 2first arg: yfirst arg: yfirst arg: y za b c還有一些特殊參數: $$ 儲存當前(shell)進程的PID, $! 儲存最近轉入後台啟動並執行進程的PID, $? 儲存上一個命令的返回狀態代碼。 特殊參數和位置參數不能通過指派陳述式改變。 運算式可以用 let "expr" 或 ((expr)) 對算術運算式求值,多個運算式可以分別用空格和逗號分開。 $ x=1 y=1 z=0$ let "x = x * 10 + y" z=z+1$ echo $x $y $z11 1 1$ ((x = x * 10 + y, z = z + 1))$ echo $x $y $z111 1 2條件運算式用 [[expr]] 求值。有個比較特別的運算子是 = ,在條件運算式中可以用它來判斷相等。 運算子BASH支援絕大部分C語言的運算子,有些運算子增加了一些特定文法結構中的含義,如管道。 控制流程if...thenif...then 的文法如下: if test-command then command[elif test-command then command ...][else command] fi為了減少縮排,常常用 ; 將 then 寫到上一行。 test-command 為測試命令,可以用 test 命令進行測試,但一般使用它的同義字 [] 。 # 檢查參數個數if [ $# -eq 0 ]; then # 等價於:if test $# -eq 0; then echo "Usage: cmd arg" 1>&2 exit 1fi對於數值的測試,可以使用: -eq 等於-ne 不等於-gt 大於-ge 大於等於-lt 小於-le 小於等於字串的比較可以使用 = 和 != 。 下面是一些和檔案相關的檢查選項: -e 檢查檔案是否存在-d 檢查檔案是否存在且是目錄-f 檢查檔案是否存在且是普通檔案-s 檢查檔案是否存在且大於0位元組-r 檢查檔案是否存在且可讀-w 檢查檔案是否存在且可寫-x 檢查檔案是否存在且可執行forfor 的文法如下: for var[ in list]do commanddoneseq 為可展開為列表的運算式。可以省略 in list ,這時列表為命令的參數,即 $@ 。 # whos指令碼,列印使用者名稱和全名 Usage: whos user ...for user; do gawk -F: '{print $1, $5}' /etc/passwd | grep -i "$user"donewhile和untilwhile 和 until 類似,區別是 until 在 do 分支執行後測試,並且是測試結果為假時迴圈,測試結果為真時跳出迴圈。 文法為: while test-commanddo commanddone until test-commanddo commanddone# 尋找拼字錯誤的詞while read line; do if ! grep "^$line$" "$1" > /dev/null; then echo $line fidone # 猜名字rightname=yeolaruntil [ "$name" = "$rightname" ]; do echo -n "Guess: " read namedoneecho "Good, you've got it."break和continuebreak 和 continue 可以用於在 for 、 while 和 until 語句中跳出迴圈和繼續下一迴圈。 casecase 用於多路選擇。文法為: case test-command in pattern) command ;; [pattern) command ;; ...]esacpattern 可以使用 * 匹配任一字元串, ? 匹配單個字元, [...] 給出可匹配的字元, | 分離不同的選擇。 # 命令選擇echo -e "\ncmds: A for date, B for who, C for pwd.\n"echo -n "Enter A, B or C: "read ccase "$c" in a|A) date ;; b|B) who ;; c|C) pwd ;; *) echo "Invalid choice: $c" ;;esacselectselect 顯示一個菜單,根據使用者的選擇給變數賦予相應的值,然後執行命令。退出 select 可以使用 break,或者 exit 退出整個指令碼。 select var[ in list]do commanddone和 for 一樣,省略 in list 會用命令參數代替。 PS3 設定 select 的提示符,一般會設定為需要的提示句。 # 命令菜單PS3="Choose what you want to do: "select c in date who pwd exit; do if [ "$c" == "" ]; then echo -e "Invalid choice.\n" continue elif [ $c = exit ]; then echo "quit" break fi echo "You choose: $c" if [ $c = date ]; then date elif [ $c = who ]; then who elif [ $c = pwd ]; then pwd fi echo ""done檔案描述符在BASH中,使用 exec 命令執行檔案描述符相關的操作: exec n> outfile 開啟outfile作為輸出檔案,分配檔案描述符nexec n< infile 開啟infile作為輸入檔案,分配檔案描述符nexec n<&m 開啟或重新導向檔案描述符n,作為檔案描述符m的副本exec n<&- 關閉檔案描述符n內建命令前面已經提到了很多BASH內建命令,這裡做個總結和補充。 : 返回0或 true (置空內部命令). 把shell指令碼當作當前進程的一部分執行bg 掛起任務break 跳出迴圈cd 改變工作目錄continue 繼續下一迴圈echo 顯示eval 掃描並計算命令列exec 執行shell指令碼或程式並替換掉當前進程exit 從當前shell退出export 將變數放到被調用的環境中fg 將背景工作移到前台getopts 分析讀取shell指令碼的參數jobs 列出背景工作kill 向進程或作業發送訊號pwd 顯示當前工作目錄read 從標準輸入中讀一行readonly 聲明變數為唯讀set 列出全部變數,設定shell特性,設定命令列參數shift 左移命令列參數test 比較times 顯示當前shell及其子進程的已耗用時間trap 捕獲訊號type 顯示參數給出的命令的相關資訊umask 返迴文件建立的掩碼,設定掩碼unset 刪除變數或函數wait 等待後台進程結束read 支援一些選項: -a array 輸入的單詞作為 array 的元素-d delim 使用 delim 代替換行來終止輸入-e 使用Readline庫來擷取輸入(輸入來自鍵盤時)-n num 讀取 num 個字元後返回-p prompt 以 prompt 作為輸入的提示資訊-s 在終端上不列印字元-un 從檔案描述符為n的檔案輸入有個特殊的變數 REPLY ,儲存讀取的輸入。 getopts 的文法為 getopts optstr var[ arg ...] , optstr 給出合法的字母選項, var 儲存每次接收的選項的值, arg 為將處理的參數,省略將預設處理命令列參數。 optstr 以 : 開始時由指令碼負責產生錯誤資訊,否則由 getopts 自己產生。 optstr 用字母后的 : 表示選項接受值, OPTARG 儲存和選項相關的值。OPTIND 儲存選項的索引,起始值為1。 exec 既可執行指令碼又可執行程式,它不建立新進程,把當前(shell)進程替換為要執行的內容。 trap 的用法是 trap ['command'] [signal] ,它捕獲訊號,執行 command ,如果沒有 command ,那麼重設trap 。 trap '' 2 15 # 捕獲並忽略中斷trap 'echo Interrupted.; exit 1' INT # 捕獲中斷,列印資訊並退出kill 給進程發送訊號,如終止進程。後面會詳細講有關進程的內容。 shell指令碼根據本篇介紹的內容和前兩篇的一些知識就可以編寫shell指令碼了。 像Python指令碼一樣可以用 #! 為指令碼定義解譯器。 #!/bin/bash# 或者:#!/usr/bin/env bash