Skip to main content

Shell Script 函式

建立 Shell script

chmod +x test.sh
  • 執行檔案
./demo.sh
  • Shell script 開頭
!/bin/sh (或者是 #!/bin/bash)

這裡的 #! 後面要定義的就是命令的解釋器(command interpreter)﹐如果是 /bin/bash 的話﹐那下面的句子就都用 bash 來解釋。

輸入

read –p "提示" 變數資料 程式執行時會在命令列出現提示字元以提示使用者要輸入的是什麼資料,同樣,輸入後的資料便存在該變數名稱中。

read –t N 變數名稱 來輸入,系統會限制使用者必須在 N 秒內輸入,超過 N 秒,則輸入無效。

輸出

echo $變數名稱printf $變數名稱 來輸出。由於 echo 指令內定會自動換行,使用 printf 這個指令來輸出字串就會直接接在後面。

read -p "Please enter your age:" Y_AGE
echo "你輸入的年齡是 $Y_AGE 歲"

變數

  1. 變數名稱 = 值 宣告變數或為變數賦值,等號兩端記得不能有空白!
  2. $變數名稱 呼叫變數的值時,變數名稱之前要加上一個 $ 符號。也有人會寫作 ${變數名稱} ,而花括號主要是輔助了解變數的範圍。

若是值內有空白則需要使用 ‘’ 或 “” 嘎包凱!

  1. 刪除變數使用 unset

  2. 預設的特殊變數如下:

  • $? :表示上一個指令的離開狀況,一般指令正常離開會傳回 0。不正常離開則會傳回 1、2 等數值。$1 :表示輸入的第一個參數,$2 則為第二個參數,依此類推。$0 :shell script 的檔名。(包含路徑)
  • $0 :shell script 的檔名。(包含路徑)
  • $@ :即代表 $1, $2,....直到所有參數結束。也就是說 $@ 代表了 “$1” “$2” “$3”….。
  • $* :所有參數無間隔的連在一起,成為單一個參數。也就是說 $* 代表了 “$1 $2 $3…”
echo ${myVariable} 會輸出 “Hello World!”
./myscript.sh arg1 arg2 arg3

那麼在程式中可以使用這些變數來訪問這些參數的值:

echo "第一個參數是:$1"
echo "第二個參數是:$2"
echo "第三個參數是:$3"

使用變數時,我們需要在變數名前加上符號 $

  1. 字串:
  • 字串兩旁並不用任何符號框住。宣告方式為:變數名稱=字串。
  • 字串中不能包含$,會被當成呼叫變數用的符號。
  • 「連續或單一個空白字元」會被當成「單獨一個空白字元」。
  • 若要使字串中包含',可用反斜線 \ 跳脫。
  1. 雙引號""中若含有變數$var,會先將變數轉換成其實際的值,單引號''則會將$var當成是一個值,而不會作轉換動作。
echo "你們輸入的年齡是 $Y_AGE + $F_AGE 歲"
echo "你們輸入的年齡是 $((Y_AGE + F_AGE)) 歲"

四則運算

整數的四則運算和求餘數,並非直接輸入程式碼就好。

若是直接輸入則會變成字串相加:

n=1
m=2
echo $n+$m

則會輸出:

1+2

要執行運算式,其語法應為:$((運算式))

n=1
m=2
echo $((n+m))

才會輸出

3

在 Bash Shell 中內建原生不支援運算式,但我們可以使用 expr、awk 等指令來支援實現運算式。

#!/bin/bash

read -p "Please enter your age:" Y_AGE
read -p "Please enter your friend's age:" F_AGEsum1=$Y_AGE + $F_AGE
sum2=`expr $Y_AGE + $F_AGE`
sum3=$((Y_AGE + F_AGE))echo "你們輸入的年齡是 $Y_AGE + $F_AGE 歲"
echo "你們輸入的年齡是 $((Y_AGE + F_AGE)) 歲"
#Bash Shell 中內建原生不支援運算式,所以無法顯示
echo "你們輸入的年齡是 $sum1 歲"
echo "你們輸入的年齡是 $sum2 歲"
echo "你們輸入的年齡是 $sum3 歲"

布林值

  • 宣告變數為真:變數名稱=true
  • 宣告變數為假:變數名稱=false

矩陣

宣告矩陣變數,語法如:變數名稱=("一" "二" "三" …) 每個元素間以空格做區分。

直接呼叫矩陣會顯示矩陣變數的首元素。 如:

age=("34" "25" "29")
echo $age

執行後會顯示 34。

而使用echo ${age[1]}執行後就會依照[]中的次數顯示,此範例中會顯示 25,因矩陣索引由 0 開始計算。

運算符

字串比較運算符

=:等於(字串相等)
!=:不等於(字串不相等)
<:小於(按字典序比較)
>:大於(按字典序比較)
-z:檢查字串是否為空(長度為零)
-n:檢查字串是否非空(長度大於零)

數字比較運算符

-eq:等於(數字相等)
-ne:不等於(數字不相等)
-lt:小於(數字小於)
-le:小於或等於(數字小於或等於)
-gt:大於(數字大於)
-ge:大於或等於(數字大於或等於)
#!/bin/bash
# 範例:檢查文件的行數是否大於特定數量

filename ="test.txt"
最小行數=10

#使用 wc 指令獲取文件的行數
行數=$(wc -l < "$filename")

#使用 if 條件句檢查行數是否大於最小行數
if [ $行數 -gt $最小行數 ]; then
echo "$filename 的行數 ($行數 行) 大於 $最小行數 行"
else
echo "$filename 的行數 ($行數 行) 小於 $最小行數 行"
fi

文件測試運算符

使用文件測試運算符(File Test Operators),用於檢查文件的不同屬性和狀態。

-e FILE:如果 FILE 存在,則為真。
-f FILE:如果 FILE 存在且為一個檔案,則為真。
-d FILE:如果 FILE 存在且為一個目錄,則為真。
-s FILE:如果 FILE 存在且檔案大小不為零,則為真。
-r FILE:如果 FILE 存在且可讀取(有讀取權限),則為真。
-w FILE:如果 FILE 存在且可寫入(有寫入權限),則為真。
-x FILE:如果 FILE 存在且可執行(有執行權限),則為真。
-L FILE:如果 FILE 存在且為一個符號連結(軟連結),則為真。
-p FILE:如果 FILE 存在且為一個命名管道(FIFO),則為真。
-c FILE:如果 FILE 存在且為一個字元特殊文件,則為真。
# 檢查文件是否存在
if [ -e 文件名 ];
then
echo "文件存在"
else
echo "文件不存在"
fi

# 檢查文件是否為檔案
if [ -f 文件名 ];
then
echo "文件是一個檔案"
else
echo "文件不是一個檔案"
fi
# 檢查文件是否為目錄
if [ -d 目錄名 ];
then
echo "文件是一個目錄"
else
echo "文件不是一個目錄"
fi

流程控制

條件語句 if else

首先判斷「 if 」後的條件,如果條件為 true,則執行「 then 」和「 else 」之間的命令。如果條件為 false,則執行「 else 」後的命令,用 if 為條件語句開頭,fi 為條件語句結尾。

if 條件
then
# 如果條件為True,執行這裡的命令else
# 如果條件為False,執行這裡的命令fi
# 範例:檢查變數x是否等於10
x=10
if [ "$x" -eq 10 ]
then
echo "x等於10"
else
echo "x不等於10"
fi

條件語句 if … elif … fi:

首先評估「 if 」後的條件 1。如果條件 1 為 true,則執行相應的命令,如果條件 1 為 false,則繼續評估「 elif 」後的條件 2,以此類推。如果所有條件都為 false,則執行「 else 」後的命令。

if 條件1
then
# 如果條件1為真,執行這裡的命令elif 條件2
then
# 如果條件2為真,執行這裡的命令else
# 如果以上所有條件都不滿足,執行這裡的命令fi
# 範例:根據不同的分數顯示不同的評級:
score=85
if [ "$score" -ge 90 ]
then
echo "評級:A"
elif [ "$score" -ge 80 ]
then
echo "評級:B"
elif [ "$score" -ge 70 ]
then
echo "評級:C"
else
echo "評級:不及格"
fi

條件語句 case

case 語句用於執行多重選擇的命令,根據匹配的條件執行相應的命令。基本的 case 語法結構如下:

case 值 in
條件1)
條件 1 匹配時執行的命令
;;
條件2)
條件 2 匹配時執行的命令
;;
*)
沒有任何匹配時執行的命令
;;
esac
#!/bin/bash
# 範例:檢查用戶輸入的文件名稱,然後使用 case 語句檢查不同的選項。
#提示用戶輸入文件名echo "請輸入文件名:"
read filename
#使用case語句檢查文件狀態case "$filename" in
-e)
if [ -e "$1" ]; then
echo "文件存在。"
else
echo "文件不存在。"
fi
;;
-d)
if [ -d "$1" ]; then
echo "這是一個目錄。"
else
echo "這不是一個目錄。"
fi
;;
-r)
if [ -r "$1" ]; then
echo "文件可讀。"
else
echo "文件不可讀。"
fi
;;
-w)
if [ -w "$1" ]; then
echo "文件可寫。"
else
echo "文件不可寫。"
fi
;;
-x)
if [ -x "$1" ]; then
echo "文件可執行。"
else
echo "文件不可執行。"
fi
;;
*)
echo "請輸入有效的選項:"
echo "-e 檢查文件是否存在"
echo "-d 檢查是否為目錄"
echo "-r 檢查文件是否可讀"
echo "-w 檢查文件是否可寫"
echo "-x 檢查文件是否可執行"
;;
esac

for 迴圈

for 迴圈用於遍歷一個列表或一個範圍,對列表中的每個元素執行相同的命令。基本語法如下:

for 變數 in 列表; do
執行的命令
done
#!/bin/bash
# 使用for迴圈印出簡單的三角形範例

for ((i=1; i<=5; i++))
do
for ((j=1; j<=i; j++))
do
echo -n "*"
done
echo# 換行done
*

*
*

for 使用方法和一般程式語言類似,同樣可以針對條件使用 break、continue 來跳出或是跳過迴圈。

#!/bin/bash

for loop in 1 2 3;
do
echo "number: $loop"
done

for 還有另外一種寫法,與現在很多主流的程式語言很類似,也支援 <><=>=

#!/bin/bash

echo -n "請問你要幾個檔案:"
read F
for ((i=1 ; i<=F ; i++))dotouch $i.js
echo $idone
echo "已經給你 $F 個檔案囉了!"

while 迴圈

while迴圈會在條件為真時一直執行指定的程式碼塊,直到條件變為假為止。可用於處理需要重複執行,但不知道具體次數的情況。

while 條件
do
# 當條件為真時執行的程式碼done
#!/bin/bash
# 範例:while迴圈計算 1 到 5 的總和
sum = 0
i = 1
while [ $i -le 5 ]
do
sum = $((sum + i))
i = $((i + 1))
done
echo "總和: $sum"

若是需要設定一個條件直到該條件為止,可以使用 while,但要注意避免無限迴圈狀況。而 while 有三種模式:

  • 在條件成立時,就會不斷執行迴圈內容:
#!/bin/bash

echo -n "請問你要幾個檔案:"
read FINDEX=1
# 當條件成立,就會不斷執行(le表示小於或等於)
while [ $INDEX -le $F ]
do
# 輸出
touch $INDEX.js
echo -n "$INDEX"
# INDEX 的值會加 1
(( INDEX++ ))
done
echo ""echo "已經給你 $F 個檔案囉了!"
  • 無窮迴圈:直到外力介入才會停止
#!/bin/bash

echo "按下 Ctrl + C 中斷…"LENGTH=0
while :
do
echo -ne "\r["
sleep 0.2
while [ $LENGTH -le 10 ]
do
sleep 0.1
echo -n ">"
(( LENGTH++ ))
done
LENGTH=0
echo -en "\r "
done
  • 輸入一文字檔,在迴圈中一次只讀取一行。首先要先準備一個檔案,檔名是 dophin.txt
#!/bin/bash

echo -n "請輸入要讀取的文字檔名稱:"
read FNINDEX=1
while read line
do
echo "イルカポリス: $line"
(( INDEX++ ))
done <$FN

until

直到某個條件結束可以使用 until 來進行,就像 while 的相反。

#!/bin/bash

echo -n "請問你要幾個檔案:"
read F
counter=0
until [ $counter = $F ]; do
((counter++)) #放在後面會變無限迴圈
echo $counter
touch $counter.js

done
echo "已經給你 $F 個檔案囉了!"

函式 Function 結構

函式結構包括函式名稱、函式的程式碼和可選的返回值。函式內部的程式碼可以使用參數來接收傳遞給函式的值,並且可以執行各種操作。

function 函式名稱 {
# 函式的程式碼# 可以使用傳遞給函式的參數# 函式的操作# ...# 返回值(可選)
}

如何使用函式來建立一個簡單的CI/CD(持續集成/持續交付)程式的範例,該程式可以自動構建和部署一個網站應用程序。實際的CI/CD環境中,可以根據需要擴展這些函式,並將其結合到CI/CD工具(如Jenkins、Gitlab、GitHub Actions等)中以自動執行。

#!/bin/bash

# 函式:構建應用程序build_app() {
echo "開始構建應用程序..."
# 在此處執行構建命令,例如使用npm、docker build等# 構建完成後將應用程序的檔案放在指定目錄中echo "應用程序構建完成"
}

# 函式:測試應用程序test_app() {
echo "開始測試應用程序..."
# 在此處執行測試命令,例如使用Jest、Mocha、Selenium等# 檢查測試結果,如果測試失敗,可以中止部署echo "測試完成,一切正常"
}
# 函式:部署應用程序deploy_app() {
echo "開始部署應用程序..."
# 在此處執行部署命令,例如使用rsync、scp、Docker Compose等# 部署完成後,應用程序將在目標伺服器上運行echo "應用程序部署完成"
}

# 主程式echo "CI/CD流程開始"

# 呼叫函式依次執行CI/CD步驟
build_app
test_app
deploy_app

echo "CI/CD流程完成"

函式基本架構如下:

  • 函式名稱(function 關鍵字為選擇性)
  • 是否有傳入參數
  • 函式內操作
  • 是否有回傳值

函式的特殊用法如下:

  • $N 來擷取第N個參數的值(N是整數,從1開始)。
  • $# 可用來擷取參數的數目。
  • $* 可擷取所有輸入參數。
  • shift 指令可以解除第一個參數的設定,並使所有參數「往前靠攏」。此時 $N 的值會被原本 $N+1 的值所取代,$#的值也會減 1,$* 也會改變。
function get_mean(){
ans=0
n=$# #將輸入參數的數目存入n
echo "the mean of "$*":" #輸出所有參數值
while [ $# -ne 0 ] #判斷輸入的參數是否小於等於零
do
ans=$(($ans+$1)) #擷取第1個參數
shift
#使所有參數向前靠攏,
#在本例中第一圈 $#-1 變 3; $N+1 變2; $* 從 1 變 6
done
ans=$(($ans/n)) #計算中位數
echo $ans
}
get_mean 1 6 10 32