Shell:結構化語句

来源:https://www.cnblogs.com/Rohn/archive/2020/07/04/13234419.html
-Advertisement-
Play Games

ver: 1.0 博客:https://www.cnblogs.com/Rohn 本文介紹了Shell常用的結構化語句。 數組 數組(Array)是若幹數據的集合,其中的每一份數據都稱為元素(Element)。 Bash只支持一維數組(不支持多維數組),初始化時不需要定義數組大小,理論上可以存放無限 ...


目錄

數組

數組(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-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] 表示 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迴圈體中的語句,也就是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. 重覆執行2、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,還有另外三個比較重要的變數:

  • $#可以獲取傳遞的參數的個數;
  • $@或者$*可以一次性獲取所有的參數

您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 使用博客園寫博客也有2年有餘了,對博客園是有一種莫名的親切感和深刻的感情的,這2多年來一直堅持寫著博客,也是對自己的一個很好的技術歷程總結。每次學習了一些新的技術,或者有一些感興趣的方向,都會通過隨筆進行記錄,有時候也會總結很多自己的開發成果,隨著技術路線的成熟,基本上是分享我的.NET相關技術。 ...
  • vs2019創建webapi 1.創建新的項目 2.選擇.NET CORE的ASP .NET CORE WEB應用程式 3.定義項目名稱和存放地點 4.選擇API創建項目 5.刪除原本的無用的類 6.添加新的方法類 7.設置路由 using Microsoft.AspNetCore.Componen ...
  • 前言 IdentityServer4 是為ASP.NET Core系列量身打造的一款基於 OpenID Connect 和 OAuth 2.0 認證的框架 IdentityServer4官方文檔:https://identityserver4.readthedocs.io/ 看這篇文章前預設你對Id ...
  • 在i.MXRT所有Flash下載演算法里,痞子衡認為Segger J-Link版的Flash下載演算法是最應該掌握的,畢竟Segger提供了完善的軟體工具支持(Jlink commander、J-Flash、Ozone),既可獨立使用,也可嵌入其他MCU開發環境中使用(實際上它與Keil演算法文件是相容的... ...
  • 最近發現了一個好玩,有趣的終端連接工具mobaxterm。Linux下有很多終端工具例如CRT,Xshell,但小伙伴就有疑問問什麼要用mobaxterm, 主要是mobaxterm是開源的免費的(其他都是收費的)。 廢話不多說我們立即進入正題。 下載與安裝。 0.打開你的瀏覽器:用CV大法進入官網 ...
  • 冒泡排序: 演算法重覆走訪要排序的數列,一次比較兩個元素,如果它們順序錯誤就交換它們的位置,這樣最大的數就到了最後,重覆操作即可得到有序數列。 冒泡排序演算法運行: 1. 比較相鄰的元素。如果第一個比第二個大,就交換他們兩個。 2. 對每一對相鄰元素作同樣的工作,從開始第一對到結尾的最後一對。在這一點, ...
  • 以下內容,來自網路資料整理和個人安裝使用結果。後續會持續更新 ...
  • 由於一些原因,我重新安裝了系統並把之前的鏡像與虛擬機刪除了,現在又全新安裝一次CenOS6.7,順便查缺補漏,帶領各位讀者一起安裝。 (本文適合小白/新人,大佬們請忽略),帶有可選步驟的可以忽略,1-20是VMware軟體的設置,系統的安裝從21-45條開始,剩餘部分是後續配置建議。如發現問題或有疑 ...
一周排行
    -Advertisement-
    Play Games
  • C#TMS系統代碼-基礎頁面BaseCity學習 本人純新手,剛進公司跟領導報道,我說我是java全棧,他問我會不會C#,我說大學學過,他說這個TMS系統就給你來管了。外包已經把代碼給我了,這幾天先把增刪改查的代碼背一下,說不定後面就要趕鴨子上架了 Service頁面 //using => impo ...
  • 委托與事件 委托 委托的定義 委托是C#中的一種類型,用於存儲對方法的引用。它允許將方法作為參數傳遞給其他方法,實現回調、事件處理和動態調用等功能。通俗來講,就是委托包含方法的記憶體地址,方法匹配與委托相同的簽名,因此通過使用正確的參數類型來調用方法。 委托的特性 引用方法:委托允許存儲對方法的引用, ...
  • 前言 這幾天閑來沒事看看ABP vNext的文檔和源碼,關於關於依賴註入(屬性註入)這塊兒產生了興趣。 我們都知道。Volo.ABP 依賴註入容器使用了第三方組件Autofac實現的。有三種註入方式,構造函數註入和方法註入和屬性註入。 ABP的屬性註入原則參考如下: 這時候我就開始疑惑了,因為我知道 ...
  • C#TMS系統代碼-業務頁面ShippingNotice學習 學一個業務頁面,ok,領導開完會就被裁掉了,很突然啊,他收拾東西的時候我還以為他要旅游提前請假了,還在尋思為什麼回家連自己買的幾箱飲料都要叫跑腿帶走,怕被偷嗎?還好我在他開會之前拿了兩瓶芬達 感覺感覺前面的BaseCity差不太多,這邊的 ...
  • 概述:在C#中,通過`Expression`類、`AndAlso`和`OrElse`方法可組合兩個`Expression<Func<T, bool>>`,實現多條件動態查詢。通過創建表達式樹,可輕鬆構建複雜的查詢條件。 在C#中,可以使用AndAlso和OrElse方法組合兩個Expression< ...
  • 閑來無聊在我的Biwen.QuickApi中實現一下極簡的事件匯流排,其實代碼還是蠻簡單的,對於初學者可能有些幫助 就貼出來,有什麼不足的地方也歡迎板磚交流~ 首先定義一個事件約定的空介面 public interface IEvent{} 然後定義事件訂閱者介面 public interface I ...
  • 1. 案例 成某三甲醫預約系統, 該項目在2024年初進行上線測試,在正常運行了兩天後,業務系統報錯:The connection pool has been exhausted, either raise MaxPoolSize (currently 800) or Timeout (curren ...
  • 背景 我們有些工具在 Web 版中已經有了很好的實踐,而在 WPF 中重新開發也是一種費時費力的操作,那麼直接集成則是最省事省力的方法了。 思路解釋 為什麼要使用 WPF?莫問為什麼,老 C# 開發的堅持,另外因為 Windows 上已經裝了 Webview2/edge 整體打包比 electron ...
  • EDP是一套集組織架構,許可權框架【功能許可權,操作許可權,數據訪問許可權,WebApi許可權】,自動化日誌,動態Interface,WebApi管理等基礎功能於一體的,基於.net的企業應用開發框架。通過友好的編碼方式實現數據行、列許可權的管控。 ...
  • .Net8.0 Blazor Hybird 桌面端 (WPF/Winform) 實測可以完整運行在 win7sp1/win10/win11. 如果用其他工具打包,還可以運行在mac/linux下, 傳送門BlazorHybrid 發佈為無依賴包方式 安裝 WebView2Runtime 1.57 M ...