Linux Shell Script 初學

Linux Shell Script 初學

2021, Jul 20    

身為一個軟體工程師在 Linux 上操作指令是必須要學習的,雖然本人也是工作後才比較常用到😅,不過常常會有需要打一大串指令或是操作一些複雜邏輯的時候,這時候就可以撰寫 shell script 幫助處理複雜的指令,可以做到自動化的處理,是可以幫助工程師偷懶的利器,這篇主要做些簡單的筆記幫助自己不要忘記

前言

首先要知道 shell script 其實不是一種程式語言,他的概念比較像是把指令腳本化,執行上類似直譯式的語言,因此 shell script 的使用上非常的彈性,只要是你可以在 bash 上直接使用的指令,shell script 也都可以使用,也因此要先對 linux 的基本指令操作有些了解才知道該撰寫什麼

Hello world

第一個 script 不免俗地來寫個 Hello world.sh

#!/bin/bash
echo -e "Hello world!!!\n"

第一行的 #!/bin/bash 表示這個腳本的執行環境,然後撰寫完之後一定會發現不能執行,那是因為權限的問題,預設撰寫文本是不會有執行權限的,透過 ls -l 可以看到檔案的權限,然後透過下面指令來給予執行權限

chmod +x "Hello world.sh"

這樣就能成功執行了

$ ./test.sh
Hello world!!!

變數

寫程式當然要先知道怎麼做變數命名,不過要注意的是 shell script 的所有變數都是字串,沒有什麼複雜的型態問題

test_var=123
test_var="123"
test_var='123'

以上三個寫法是一樣的,要注意的是等號的左右不能有空格,使用變數的方式如下,加不加花括號都可以

echo "${test_var}"
echo "$test_var"

特殊變數

shell script 有一些預設的特別變數,用來幫助傳入參數進行判斷與處理

變數 描述
$0 執行的 shell script 檔名
$n n 從 1 開始,表示輸入的第幾個參數
$# 表示總共傳入幾個參數
$* 表示傳入的所有參數,用空格隔開
$@ 表示傳入的所有參數,每個參數用 " 隔開
$? 前一個指令的回傳狀態
$$ 當前 shell script 的執行 PID

運算

前面說到 shell script 的變數都是字串,那要怎麼做數學運算呢,必須要透過一些特別的關鍵字才能做到

基本的像是 expr,要注意的是運算子的左右必須要空格,可以使用的運算子跟大部分的程式語言都大致相同

result = `expr 1 + 1`
echo ${result}

還有一種比較直覺的做法是用 let,這個寫法要注意不能有空白,不過寫起來較直覺

let a=1+1
let b=a+2
let a++
let a+=2

還有一種神奇的表示法 $((...)) 或是 $[...],可以在兩種表示法內寫入運算式就會轉成變數,而且有沒有空白都沒關係

result=$((1+1))
result=$((result+1))
((result+=10)) # 也可以直接在內做運算不加上 $ 號的話就不會轉成變數輸出,但結果一樣會留在 result,須注意用 [] 不能用此用法
((a=1+1,b=2+1,c=3+1)) # 多個運算式可以用 , 分開表示

雖然用括號的方式看起是最簡單的,但太多的括號個人覺得有點不好讀,所以自己比較喜歡的還是寫 let

流程控制

這部分個人覺得最麻煩的是,空白的部分都是不能夠省略的,只要有打錯的就會運作錯誤,這點要特別注意

if then else

基本的 if 結構如下,有趣的是 if 的結尾是顛倒過來的 fi,這點蠻有趣的,然後判斷式是用 [] 來表示,如果要多條件判斷就需要多個 []

if [ $a == $b ]; then
    echo "a == b"
elif [ $a != $b ]
    echo "a != b"
else
    echo "不可能發生"
fi

然後是邏輯運算子有點不一樣,不能直接用 >< 來表示,而是如下表

符號 意義
-gt 大於
-lt 小於
-ge 大於等於
-le 小於等於

示範一個多條件與比較運算子的用法

if [ $a -gt 0 ] && [ $a -lt 100 ]; then
    echo " 0 < a < 100 "
fi

case

類似於 switch case 的感覺,用做多分支判斷

city='Kaohsiung'

case $language in
    Kaohsiung*) echo "高雄市"
    ;;
    Taipei*) echo "台北市"
    ;;
    Tainan*) echo "台南市"
    ;;
    *) echo "找不到"
esac

迴圈

迴圈也是在自動化工作中非常重要的一環,或者說絕大部分想要偷懶的時候都是要用到迴圈的時候XD

for

shell script 的 for 有多種表示方法,也是有點混亂

for i in 1 2 3 4 5; do
    echo "number: $i"
done

上面寫法比較像是 foreach 的感覺,其中的 1 2 3 4 5 也可以用一個變數帶入

list="1 2 3 4 5"
for i in $list; do
    echo "number: $i"
done

或是有個比較直覺的寫法

for i in {1..5}; do
    echo "number: $i"
done

這個寫法也可以再變成,最後的 ..2 代表 step,也就是每次加 2,所以會輸出 1 3 5

for i in {1..5..2}; do
    echo "number: $i"
done

還有一種基本上跟程式語言的寫法沒什麼不同

for ((i=1;i<=5;i++)); do
    echo "number: $i"
done

while

while 也是一般程式語言常見的功能,寫法如下

let i=1
while [ $i -le 5 ]; do
    echo "number: $i"
    let i+=1
done

until

until 比較特別一點,是一般程式語言沒有的功能,他其實就是 while 的另一種面向,表示直到條件成立前都執行

let i=1
until [ $i -gt 5 ]; do
    echo "number: $i"
    let i+=1
done

function

隨著越來越複雜的自動化功能,有些 script 也可以被寫成函數並抽象化

function count(){
    for ((i=1;i<=5;i++)); do
        echo "number: $i"
    done
}

count # 使用時當作 command 來使用即可

呼叫 function 時就像使用 command 一樣,而傳遞參數的方式也相同直接帶在後面即可

function count(){
    for ((i=1;i<=$1;i++)); do
        echo "number: $i"
    done
}

count 5

而前面有提到一個特殊變數 $?,其實最常用到的地方就是 function 的回傳

function sum(){
    let sum=0
    for ((i=1;i<=$1;i++)); do
        let sum+=$i
    done
    return sum
}

sum 5
echo "sum 1~5: $?"

結語

本篇是一個 shell script 的簡單筆記,開始接觸到 Linux 一定都會想使用 shell script 因為太多指令常常要下,實在很麻煩,但由於常常在寫的時候會忘記一些細節,導致常常要上網查,所以乾脆記錄一下