Shell:結構化語句

數組

數組(Array)是若干數據的集合,其中的每一份數據都稱爲元素(Element)。git

Bash只支持一維數組(不支持多維數組),初始化時不須要定義數組大小,理論上能夠存放無限量的數據。正則表達式

與大部分編程語言相似,數組元素的下標由0開始。express

Shell數組用括號來表示,元素用"空格"符號分割開。格式以下:編程

array_name=(ele1  ele2  ele3 ... elen)

Tips:賦值號=兩邊不能有空格,必須緊挨着數組名和數組元素。數組

獲取數組中的元素要使用下標[],下標能夠是一個整數,也能夠是一個結果爲整數的表達式;固然,下標必須大於等於0。格式以下:bash

${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-elsecase-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:ifelif後邊都得跟着then

語句的執行邏輯:

  • 若是condition1成立,那麼執行statement1,若是不成立,則執行elif語句;
  • 若是elif語句不成立,則執行else語句;

case-in語句

當分支較多,且判斷條件比較簡單時,推薦使用case-in語句。格式以下:

case expression in
  pattern1)
    statement1
    ;;
  pattern2)
    statement2
    ;;
  ...
  *)
    statementn
esac
  • expression表示表達式,既能夠是一個變量、一個數字、一個字符串,還能夠是一個數學計算表達式,或者是命令的執行結果,只要可以獲得expression的值就能夠。
  • pattern表示匹配模式,能夠是一個數字、一個字符串,甚至是一個簡單的正則表達式。

case會將expression的值與 pattern1pattern2...patternn逐個進行匹配:

  • 若是expression和某個模式(好比 pattern2)匹配成功,就會執行這模式(好比 pattern2)後面對應的全部語句(該語句能夠有一條,也能夠有多條),直到碰見雙分號;;才中止;而後整個case-in語句就執行完了,程序會跳出整個 case-in語句,執行esac後面的其它語句。
  • 若是 expression 沒有匹配到任何一個模式,那麼就執行*)後面的語句(*表示其它全部值),直到碰見雙分號;;或者esac才結束。*)至關於多個if分支語句中最後的else部分。

Tips:分支*)並非什麼語法規定,它只是一個正則表達式,*表示任意字符串,因此無論expression的值是什麼,*)總能匹配成功。所以,能夠沒有*)部分,若是expression沒有匹配到任何一個模式,那麼就不執行任何操做。

除最後一個分支外(這個分支能夠是普通分支,也能夠是*)分支),其它的每一個分支都必須以;;結尾,;;表明一個分支的結束,不寫的話會有語法錯誤。最後一個分支能夠寫;;,也能夠不寫,由於不管如何,執行到esac都會結束整個case-in語句。

case-inpattern部分支持簡單的正則表達式,具體來講,可使用如下幾種格式:

格式 說明
* 表示任意字符串。
[abc] 表示 a、b、c 三個字符中的任意一個。好比,[15ZH] 表示 一、五、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循環體中的語句,也就是dodone之間的語句。這樣就完成了一次循環。
  • 每一次執行到done的時候都會從新判斷condition是否成立,若是成立,就進入下一次循環,繼續執行dodone之間的語句,若是不成立,就結束整個while循環,執行done後面的其它Shell代碼。
  • 若是一開始condition就不成立,那麼程序就不會進入循環體。

死循環

格式一:

while true; do
  statements
done

格式二:

while [ 1 ]; do
  statements
done

until語句

until循環當判斷條件不成立時才進行循環,一旦判斷條件成立,就終止循環。

until condition; do
  statements
done

until循環的執行流程爲:

  • 先對condition進行判斷,若是該條件不成立,就進入循環,執行until循環體中的語句(dodone之間的語句),這樣就完成了一次循環。
  • 每一次執行到done的時候都會從新判斷condition是否成立,若是不成立,就進入下一次循環,繼續執行循環體中的語句,若是成立,就結束整個 until循環,執行done後面的其它Shell代碼。

for語句

C語言風格的 for 循環

格式以下:

for((exp1; exp2; exp3)); do
  statements
done

exp1exp2exp3是三個表達式,其中exp2是判斷條件,for循環根據exp2的結果來決定是否繼續下一次循環;

它的運行過程爲:

  1. 先執行exp1
  2. 再執行exp2,若是它的判斷結果是成立的,則執行循環體中的語句,不然結束整個for循環。
  3. 執行完循環體後再執行exp3
  4. 重複執行二、3步驟,直到exp2的判斷結果不成立,就結束循環。

for-in循環

格式以下:

for variable in value_list; do
  statements
done

variable表示變量,value_list表示取值列表。

每次循環都會從value_list中取出一個值賦給變量 variable,而後進入循環體(dodone之間的部分),執行循環體中的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 對內層和外層循環語句都有效,不但內層會跳過本次循環,外層也會跳過本次循環,其效果至關於內層循環和外層循環同時執行了不帶ncontinue

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,還有另外三個比較重要的變量:

  • $#能夠獲取傳遞的參數的個數;
  • $@或者$*能夠一次性獲取全部的參數
相關文章
相關標籤/搜索