ver: 1.0 博客:https://www.cnblogs.com/Rohn 本文介紹了Shell常用的結構化語句。 數組 數組(Array)是若幹數據的集合,其中的每一份數據都稱為元素(Element)。 Bash只支持一維數組(不支持多維數組),初始化時不需要定義數組大小,理論上可以存放無限 ...
- ver: 1.0
- 博客:https://www.cnblogs.com/Rohn
- 本文介紹了Shell常用的結構化語句。
目錄
數組
數組(Array)是若幹數據的集合,其中的每一份數據都稱為元素(Element)。
Bash只支持一維數組(不支持多維數組),初始化時不需要定義數組大小,理論上可以存放無限量的數據。
與大部分編程語言類似,數組元素的下標由0開始。
Shell數組用括弧來表示,元素用"空格"符號分割開。格式如下:
array_name=(ele1 ele2 ele3 ... elen)
Tips:賦值號
=
兩邊不能有空格,必須緊挨著數組名和數組元素。
獲取數組中的元素要使用下標[]
,下標可以是一個整數,也可以是一個結果為整數的表達式;當然,下標必須大於等於0。格式如下:
${array_name[index]}
Tips:
array_name
是數組名,index
是下標。
Shell是弱類型的,它並不要求所有數組元素的類型必須相同,例如:
arr=(10 24 'ddd' 'ab22' 5)
獲取數組所有元素
使用@
或*
可以獲取數組中的所有元素,格式如下:
${array_name[*]}
${array_name[@]}
獲取數組元素個數
使用#
來獲取數組元素的個數,格式如下:
${#array_name[@]}
${#array_name[*]}
數組合併
數組合併,就是將兩個或兩個以上的數組合併成一個個數組,格式如下:
array_new=(${array1[@]} ${array2[@]}...${arrayn[@]})
array_new=(${array1[*]} ${array2[*]}...${arrayn[*]})
刪除數組元素
使用unset
關鍵字來刪除數組元素,格式如下:
unset array_name[index]
如果不寫下標,則代表刪除整個數組所有元素,格式如下:
unset array_name
實例
測試ip是否ping通
#!/usr/bin/env bash
# Author: Rohn
# Version: 1.0
# Create Time: 2020/06/13
# Test network connectivity
arr_num=(3 11 25 32 200)
for i in ${arr_num[*]}; do
ip=192.168.110.${i}
ping -c 1 $ip >/dev/null 2>&1
if [ $? -eq 0 ]; then
echo "${ip} is ok."
else
echo "${ip} is unreachable."
fi
done
選擇結構
Shell中的選擇結構(分支結構)有兩種形式,分別是 if-else
和case-in
語句,它們都根據命令的退出狀態來判斷條件是否成立。
if-else語句
基本格式
基本結構格式:
if condition; then
statement(s)
fi
condition
是判斷條件,如果condition
成立(返回True),那麼then
後邊的語句將會被執行;如果 condition不成立(返回False),那麼不會執行任何語句。
Tips:最後必須以
fi
來閉合,fi
就是if
倒過來拼寫。
if-else
如果有兩個分支,就可以使用if-else
語句,格式:
if condition; then
statement1
else
statement2
fi
如果condition
成立,那麼then
後邊的 statement1
語句將會被執行;否則,執行else
後邊的statement2
語句。
if-elif-else
當分支比較多時,可以使用if-elif-else
結構,格式:
if condition1; then
statement1
elif condition2;then
statement2
...
else
statementn
fi
Tips:
if
和elif
後邊都得跟著then
。
語句的執行邏輯:
- 如果
condition1
成立,那麼執行statement1
,如果不成立,則執行elif
語句; - 如果
elif
語句不成立,則執行else
語句;
case-in語句
當分支較多,且判斷條件比較簡單時,推薦使用case-in
語句。格式如下:
case expression in
pattern1)
statement1
;;
pattern2)
statement2
;;
...
*)
statementn
esac
expression
表示表達式,既可以是一個變數、一個數字、一個字元串,還可以是一個數學計算表達式,或者是命令的執行結果,只要能夠得到expression
的值就可以。pattern
表示匹配模式,可以是一個數字、一個字元串,甚至是一個簡單的正則表達式。
case
會將expression
的值與 pattern1
、pattern2
...patternn
逐個進行匹配:
- 如果
expression
和某個模式(比如 pattern2)匹配成功,就會執行這模式(比如 pattern2)後面對應的所有語句(該語句可以有一條,也可以有多條),直到遇見雙分號;;
才停止;然後整個case-in
語句就執行完了,程式會跳出整個case-in
語句,執行esac
後面的其它語句。 - 如果 expression 沒有匹配到任何一個模式,那麼就執行
*)
後面的語句(*
表示其它所有值),直到遇見雙分號;;
或者esac
才結束。*)
相當於多個if
分支語句中最後的else
部分。
Tips:分支
*)
並不是什麼語法規定,它只是一個正則表達式,*
表示任意字元串,所以不管expression
的值是什麼,*)
總能匹配成功。因此,可以沒有*)
部分,如果expression
沒有匹配到任何一個模式,那麼就不執行任何操作。
除最後一個分支外(這個分支可以是普通分支,也可以是*)
分支),其它的每個分支都必須以;;
結尾,;;
代表一個分支的結束,不寫的話會有語法錯誤。最後一個分支可以寫;;
,也可以不寫,因為無論如何,執行到esac
都會結束整個case-in
語句。
case-in
的pattern
部分支持簡單的正則表達式,具體來說,可以使用以下幾種格式:
格式 | 說明 |
---|---|
* |
表示任意字元串。 |
[abc] | 表示 a、b、c 三個字元中的任意一個。比如,[15ZH] 表示 1、5、Z、H 四個字元中的任意一個。 |
[m-n] | 表示從 m 到 n 的任意一個字元。比如,[0-9] 表示任意一個數字,[0-9a-zA-Z] 表示字母或數字。 |
| |
表示多重選擇,類似邏輯運算中的或運算。比如,abc | xyz 表示匹配字元串 "abc" 或者 "xyz"。 |
用;;
&終止每個條件塊,例如:
read -n 1 -p "Type a character > "
echo
case $REPLY in
[[:upper:]]) echo "'$REPLY' is upper case." ;;&
[[:lower:]]) echo "'$REPLY' is lower case." ;;&
[[:alpha:]]) echo "'$REPLY' is alphabetic." ;;&
[[:digit:]]) echo "'$REPLY' is a digit." ;;&
[[:graph:]]) echo "'$REPLY' is a visible character." ;;&
[[:punct:]]) echo "'$REPLY' is a punctuation symbol." ;;&
[[:space:]]) echo "'$REPLY' is a whitespace character." ;;&
[[:xdigit:]]) echo "'$REPLY' is a hexadecimal digit." ;;&
esac
輸出結果如下:
Type a character > a
'a' is lower case.
'a' is alphabetic.
'a' is a visible character.
'a' is a hexadecimal digit.
迴圈結構
迴圈結構語句大致分為4種:
- while
- until
- for
- select
while語句
當條件滿足時,while
重覆地執行一組語句,當條件不滿足時,就退出while
迴圈。格式如下:
while condition; do
statements
done
執行流程如下:
- 先對
condition
進行判斷,如果該條件成立,就進入迴圈,執while
迴圈體中的語句,也就是do
和done
之間的語句。這樣就完成了一次迴圈。 - 每一次執行到
done
的時候都會重新判斷condition
是否成立,如果成立,就進入下一次迴圈,繼續執行do
和done
之間的語句,如果不成立,就結束整個while
迴圈,執行done
後面的其它Shell
代碼。 - 如果一開始
condition
就不成立,那麼程式就不會進入迴圈體。
死迴圈
格式一:
while true; do
statements
done
格式二:
while [ 1 ]; do
statements
done
until語句
until
迴圈當判斷條件不成立時才進行迴圈,一旦判斷條件成立,就終止迴圈。
until condition; do
statements
done
until
迴圈的執行流程為:
- 先對
condition
進行判斷,如果該條件不成立,就進入迴圈,執行until
迴圈體中的語句(do
和done
之間的語句),這樣就完成了一次迴圈。 - 每一次執行到
done
的時候都會重新判斷condition
是否成立,如果不成立,就進入下一次迴圈,繼續執行迴圈體中的語句,如果成立,就結束整個until
迴圈,執行done
後面的其它Shell
代碼。
for語句
C語言風格的 for 迴圈
格式如下:
for((exp1; exp2; exp3)); do
statements
done
exp1
、exp2
、exp3
是三個表達式,其中exp2
是判斷條件,for
迴圈根據exp2
的結果來決定是否繼續下一次迴圈;
它的運行過程為:
- 先執行
exp1
。 - 再執行
exp2
,如果它的判斷結果是成立的,則執行迴圈體中的語句,否則結束整個for
迴圈。 - 執行完迴圈體後再執行
exp3
。 - 重覆執行2、3步驟,直到
exp2
的判斷結果不成立,就結束迴圈。
for-in迴圈
格式如下:
for variable in value_list; do
statements
done
variable
表示變數,value_list
表示取值列表。
每次迴圈都會從value_list
中取出一個值賦給變數 variable
,然後進入迴圈體(do
和done
之間的部分),執行迴圈體中的statements
。直到取完value_list
中的所有值,迴圈就結束了。
value_list
:
- 具體的值,例如:
for i in 1 2 3 'dd';do echo $i;done
{start..end}
,例如:
# 求1到10的和
sum=0
for i in {1..10}; do
sum=$((sum+i))
done
echo $sum
- 命令的執行結果,例如:
# 求100以內偶數的和
for i in $(seq 2 2 100); do
sum=$((sum+i))
done
echo $sum
- 通配符,例如:
# 列印當前路徑.log結尾的文件
for i in *.log; do echo $i;done
Tips:若當前路徑無.log結尾的文件,則會列印
*.log
- 特殊變數,
$*
、$@
等,例如:
for i in $@; do
sum=$((sum+i))
done
echo $sum
select-in語句
select-in
迴圈用來增強交互性,它可以顯示出帶編號的菜單,用戶輸入不同的編號就可以選擇不同的菜單,並執行不同的功能,非常適合終端(Terminal)這樣的交互場景。格式如下:
select variable in value_list; do
statements
done
variable
表示變數,value_list
表示取值列表。
例如:
echo "選擇你要學習的科目:"
select i in 'Linux' 'Python' 'Java' 'C++' 'PHP'; do
echo "你選擇了${i}。"
done
結果如下:
選擇你要學習的科目:
1) Linux
2) Python
3) Java
4) C++
5) PHP
#? 5
你選擇了PHP。
#? 2
你選擇了Python。
#? 666
你選擇了。
Tips:
select
是死迴圈,輸入空值或者輸入的值無效,都不會結束迴圈,只有遇到break
語句,或者按下Ctrl+D
組合鍵才能結束迴圈。
例如:
echo "選擇你要學習的科目:"
select i in 'Linux' 'Python' 'Java' 'C++' 'PHP'; do
echo "你選擇了${i}。"
break
done
結果如下:
選擇你要學習的科目:
1) Linux
2) Python
3) Java
4) C++
5) PHP
#? 5
你選擇了PHP。
select-in
語句常和case-in
語句一起使用。
break
格式如下:
break n
n
表示跳出迴圈的層數,如果省略n,則表示跳出當前。
continue
格式如下:
continue n
n
表示迴圈的層數:
- 如果省略
n
,則表示continue
只對當前層次的迴圈語句有效,遇到continue
會跳過本次迴圈,忽略本次迴圈的剩餘代碼,直接進入下一次迴圈。 - 如果帶上
n
,比如n
的值為2,那麼continue
對內層和外層迴圈語句都有效,不但內層會跳過本次迴圈,外層也會跳過本次迴圈,其效果相當於內層迴圈和外層迴圈同時執行了不帶n
的continue
。
與break
的區別:
break
用來結束當前整個迴圈;continue
用來結束本次迴圈,直接跳到下一次迴圈,如果迴圈條件成立,還會繼續迴圈;
函數
函數的本質是一段可以重覆使用的腳本代碼,這段代碼被提前編寫好了,放在了指定的位置,使用時直接調取即可。
函數定義
格式如下:
function func_name() {
statements
[return value]
}
Tips:關鍵詞
function
是可選的,但必須在一個項目中保持一致。
說明:
function
是Shell中的關鍵字,專門用來定義函數,可以不寫,但要求在整個項目腳本中保持一致,即統一不寫或都寫;func_name
是函數名,按照約定規範,函數名後面必須帶上()
;statements
是函數要執行的代碼,也就是一組語句;return value
表示函數的返回值,其中return
是Shell關鍵字,專門用在函數中返回一個值;這一部分可以寫也可以不寫。
函數調用
調用Shell函數時可以給它傳遞參數,也可以不傳遞。如果不傳遞參數,直接給出函數名字即可,格式如下:
func_name
如果傳遞參數,那麼多個參數之間以空格分隔:
func_name param1 param2 param3...
Tips:不管是哪種調用方式,函數名字後面都不需要帶
()
函數參數
函數參數是Shell
位置參數的一種,在函數內部可以使用$n
來接收,例如,$1
表示第一個參數,$2
表示第二個參數,依次類推。
除了$n
,還有另外三個比較重要的變數:
$#
可以獲取傳遞的參數的個數;$@
或者$*
可以一次性獲取所有的參數