 
                
            Linux Shell Script 初學
身為一個軟體工程師在 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 因為太多指令常常要下,實在很麻煩,但由於常常在寫的時候會忘記一些細節,導致常常要上網查,所以乾脆記錄一下