linux的Shell指令碼程式設計
Shell指令碼的建立與執行
在子Shell中執行
當執行一個指令碼檔案時,Shell就會產生一個子Shell(即一個子程序)去執行命令檔案中的命令。
1.將檔名作為Shell命令的引數:$bash script-file
2.現將指令碼檔案的許可權改為可執行,然後執行指令碼:$script-file
在當前Shell中執行
使用source 或 “ . ”命令執行,例如:$source script-file
Shell指令碼編碼規範
以#!開頭,指明使用何種Shell解析指令碼
例如:#!/bin/bash 或 #!/usr/bin/env bash
良好的編碼過飯還要求以註釋說明如下的內容:
#指令碼名稱
#指令碼功能
#作者及聯絡方式
#版本更新記錄
#版權宣告
#對演算法做簡要說明
Shell變數操作
變數替換
功能 | 表示式 | 說明 |
---|---|---|
使用預設值 | ${var:-word} | 若var存在且非空,則值為$var; 若var未定義或為空值,則值為word,但var的值不變 |
賦予預設值 | ${var:=word} | 若var存在且非空,則值為$var; 若var未定義或為空值,則值為word,且var被賦值word |
使用預設值 | ${var:?word} | 若var存在且非空,則值為$var; 若var未定義或為空值,則輸出word,並終止指令碼 |
使用預設值 | ${var:+word} | 若var存在且非空,則值為word; 若var未定義或為空值,則返回空值,但var的值不變 |
變數字串操作
表示式 | 說明 |
---|---|
${#var} | 返回字串變數var的長度 |
${var:m} | 返回$var中從第m個字元到最後的部分 |
${var:m:len} | 返回$var中從第m個字元開始,長度為len的部分 |
${var#pattern} | 刪除${var}中開頭部分與pattern匹配的最小部分 |
${var##pattern} | 刪除${var}中開頭部分與pattern匹配的最大部分 |
${var%pattern} | 刪除${var}中結尾部分與pattern匹配的最小部分 |
${var%%pattern} | 刪除${var}中結尾部分與pattern匹配的最小部分 |
${var/old/new} | 用new替換${var}中第一次出現的old |
${var//old/new} | 用new替換${var}中所有的old |
${var/#old/new} | 用new替換${var}中開頭部分的old |
${var/%old/new} | 用new替換${var}中結尾部分的old |
變數的數值計算
運算子 | 說明 |
---|---|
+、-、*、/ | 四則運算 |
**、% | 冪運算、模運算 |
++、– | 自增、自減 |
=、+=、-=、*=、/=、%= | 賦值運算子 |
<、>、<=、>=、==、!= | 比較運算 |
&&、||、! | 邏輯運算 |
let命令,expr命令,以及最先出現的C語言風格的Shell算術運算子((…))
例如:$((a=2+3**2-1001%5))
Shell變數的輸入
read [-p ] <變數名>
讓使用者輸入,-p指定提示語句
Shell特殊變數
位置引數 | 說明 |
---|---|
$0 | 指令碼名稱 |
$n | n是大於等於1的正數,表示n個位置的引數。當n>9時,要使用${n} 形式引用 |
$# | 位置引數的個數 |
[email protected]、“[email protected]” | 將每個位置引數看成單獨字串(以空格間隔) |
$* | 將所有位置引數看成一個字串(以空格間隔) |
“$*” | 將所有位置引數看成一個字串(以$IFS間隔) |
Shell的程序狀態變數
特殊變數 | 說明 |
---|---|
$$ | 當前程序的PID |
$! | 執行在後臺的最後一個作業的PID |
$? | 在此之前執行的命令或指令碼的返回值,0表示成功,非0表示不同原因的失敗 |
$_ | 在此之前執行的命令或指令碼的最後一個引數 |
注意:每個命令都會返回一個退出狀態碼(也稱為返回狀態),0為成功,非0為不成功,非零值通常都被解釋成一個錯誤碼,在指令碼中exit n命令將會把退出狀態碼(n)傳遞給父Shell(n必須是十進位制數,範圍是0~255)
Shell 指令碼跟蹤與除錯
使用bash引數除錯指令碼
命令 | 說明 |
---|---|
bash -n < script name> | 對指令碼進行語法檢查,通常在執行指令碼之前檢查其語法是否正確 |
bash -v < script name> | 顯示指令碼中每個原始命令列及其執行結果 |
bash -x < script name> | 以除錯模式執行指令碼,對指令碼中每條命令的處理過程:先執行替換,然後顯示,再執行命令 |
在指令碼中使用set命令除錯指令碼
當指令碼檔案較長時,可以使用set命令指定除錯一段指令碼。在指令碼中使用set -x命令開啟除錯模式,使用set +x命令關閉除錯模式,例如
#!/bin/bash
echo -e “Hello $LOGNAME, \c”
set -x ###開啟除錯模式
read -p “What is your name” name
echo “Hello $name”
set +x ###關閉除錯模式
條件測試和分支結構
測試語句
格式1: test <測試表達式>
格式2: [ <測試表達式> ]
格式3: [[ <測試表達式> ]]
測試語句可以判斷命令成功或失敗、表示式為真或假,bash中沒有布林型別,0表示成功或真,非零表示失敗或假。
注意:
1.格式1和格式2是等價的,格式3時擴充套件的test命令
2.在[[ ]]中可以使用Shell萬用字元進行模式匹配
3.&&,||,< 和>操作符能夠正常的在[[ ]]中使用,但不能再[ ]中出現
4.[和[[只後的字元必須是空格,]和]]之前必須是空格
5.要讀整數進行關係運算,可以使用Shell的算術運算子 (( ))進行測試
檔案測試運算子
操作符 | 說明 |
---|---|
-e file | 檔案是否存在 |
-f file | 是否為普通檔案 |
-d file | 是否為目錄 |
-L file | 是否為符號連結檔案 |
-b file | 是否為塊裝置檔案 |
-c file | 是否為字元裝置檔案 |
-s file | 檔案長度不為0 |
-r file | 是否為只讀 |
-w file | 是否為可寫 |
-x file | 是否為可執行 |
-O file | 測試者是否為檔案屬主 |
-G file | 測試者是否為檔案同組人 |
-u file | 是否為設定了SUID的檔案 |
-g file | 是否為設定了SGID的檔案 |
-k file | 是否為設定了黏貼位的檔案 |
file1 -nt file2 | file1是否比file2新 |
file1 -ot file2 | file1是否比file2舊 |
file1 -ef file2 | file1是否與file2共用相同的i-node(連結) |
字串測試操作符
操作符 | 說明 |
---|---|
-z string | 測試字串是否為空串 |
-n string | 測試字串是否為非空串 |
string == string2 | 測試兩個字串是否相同 |
string != string2 | 測試兩個字串是否不相同 |
正數二元比較操作符
操作符功能 | 相等 | 不等 | 大於 | 大於等於 | 小於 | 小於等於 |
---|---|---|---|---|---|---|
在[]中 | -eq | -ne | -gt | -ge | -lt | -le |
在(( ))中 | == | != | > | >= | < | <= |
使用邏輯操作符
操作符功能 | “與”邏輯 | “或邏輯” | “非”邏輯 |
---|---|---|---|
在[]中 | -a | -o | -! |
在(( ))中 | && | || | ! |
分支結構迴圈
if語句
if < condition1>
then
< commands1>
[ elif < condition2 >
then
< command2 >
.. ]
[ else
< commandn > ]
fi
注意:
1.elif語句塊可以有0到多個
2.else可以為0到1個
3.條件測試可以是表示式,
4.條件測試也可以是多個命令,以最後一個命令的退出狀態為其值
5.語句塊可以是一條命令、多條命令,也可以是空命令“ : ”(冒號,表示該命令不做任何事,只返回一個退出狀態0)
case語句
case expr in
pattern1)
commands1
;;
pattern2)
commands2
;;
...
*)
commands
;;
esac
注意:
1.表示式expr按順序匹配每個模式,一旦匹配成功,則執行該模式後的命令,然後退出case
2.如果沒有匹配到模式,則執行預設值“ *) ”後的命令
3.所有模式可以含有萬用字元和邏輯或“ | ”
4.除非特殊需要,否則每個命令塊左右必須有一個雙分號“ ;; ”,與C語言的switch中的break語句功能一致
while和until
while condition
do
commands
done
當條件測試condition為真時執行迴圈體,否則退出迴圈
until condition
do
commands
done
當條件測試condition為真時結束迴圈,否則執行迴圈體
注意:bash提供了兩個迴圈控制語句
break:跳出迴圈
continue:跳出本次迴圈
for語句
foreach型迴圈
for variable in list
do
commands
done
先將列表list的變數依次賦給variable執行commands,
C語言型迴圈
for (( exp1;exp2;exp3 ))
do
commands
done
首先執行依次exp1(只執行一次),執行exp2,為真時,執行commands,在執行exp3,進入下一次迴圈,為假時退出迴圈,
seq語句與大括號表示式
語法 | 舉例 | 說明 |
---|---|---|
seq n | seq 10 | 生成序列[1…n],步長為1 |
seq m n | seq 0 10 | 生成序列[m…n],步長為1 |
seq m s n | seq 10 3 20 | 生成序列[m…n],步長為s |
{m…n} | {1…10}、{a…h} {10…1}、{h…a} |
生成序列[m…n]、[a…h],若m>n步長為1<br>生成序列[m…n]、[a…h],若m<n步長為-1 |
{m…n…s} | {1…10…3}、{a…h…3} {10…1…3}、{h…a…3} |
生成序列[m…n]、[a…h],若m>n步長為s<br>生成序列[m…n]、[a…h],若m<n步長為-s |
注意:
1.大括號表示式能生成字元序列,seq不能
2.大括號表示式能生成倒序,seq不能
select語句
select variable in list
do
commands
done
與for的foreach類似,但是會在選單項之前新增一個從1開始的序號依次呈現給使用者,序號存在變數RELAY中。
注意:
1.list列表的選單項間隔符由環境變數IFS決定
2.按數值順序排列的選單會顯示到標準錯誤輸出
3.使用者直接按鍵將重新顯示選單
4.與for迴圈類似,省略in list時等價於in “$*”
5.select是個無限迴圈,通常要配合case語句處理不同的選單及退出。可以使用break退出迴圈,或exit終止指令碼
函式
函式定義
[function] name() {
commands;
}
function可以省略
注意:函式和呼叫它的主檔案可以保持在同一個檔案中,函式定義必須出現在呼叫之前。
函式的執行方法
name 引數1 引數2 引數n
注意:
1.呼叫函式時,使用位置引數的形式傳遞引數
2.函式內的$1-$[n]、$*和[email protected]表示其接收的引數
3.函式呼叫結束後位置引數$1-$[n]、$*和[email protected]將被重置為呼叫函式之前的值
4.在主程式和函式中,$0始終代表指令碼名