2007年6月2日 星期六

基本 bash 程式設計 (2) - Variable

前言

Variable(變數),是每個程式語言中都不可或缺的重要角色之一,當然 shell script 也不例外!

不像其他程式語言,variable 擁有許多不同的型態,甚至可以是 object;在 shell script 中,variable 中儲存的內容幾乎是 character(字元)、string(字串)、number(數字)。

而關於 variable 的使用方式之前就有提過,因此這邊不再多提。


Positional Parameters

不知道是否有人曾經想過,如果執行 shell script 時想要加上多個參數,應該要怎麼下指令呢? 其實很簡單,跟執行一般程式沒兩樣,大致就是以下格式:
shell> ./script_name para1 para2 para3 ....... paraN
那在 script 中要如何使用這些參數呢? 答案就是「Positional Parameter」!

而 Positional Parameter 是以 0 1 2 3 4 .... 等數字來命名的,其中 0 是 script 名稱,而之後就是所接的參數,因此就上面的例子來說:
  • $0=script_name
  • $1=para1
  • $2=para2
  • $3=para3
  • .......(以此類推)
  • $N=paraN
由於這些參數的使用是類似其他程式語言中 index 的使用方式,才會被稱作是 Positional Parameter。

此外,當然還有一些額外且常用的 Positional Parameter,以下直接列出他們的效果:
  • $@="$1 $2 $3 ...... $N"
    為所有參數組合而成的字串,以 space 隔開,若 script 沒有參數就是空字串囉!
  • $#=N
    參數數量,若 script 沒有參數就是 0 了
  • $*="$0$IFS$1$IFS$2$IFS$3$IFS ....... $N"
    包含所有 Positional Parameter(包括 script name) 內容,且用 $IFS 所隔開的字串;一般來說 $IFS 有可能是 space、TAB、NEWLINE 三種其中一個!
    簡單來說,「$*」與「$@」的差別就是是否有包含 $0 的內容而已。
    【註】書上是這樣說,但在 Ubuntu 中實測並非如此,而是跟 $@ 是相同的

以下用一個簡單的例子來說明:

alice.sh 的內容:
#!/bin/bash
echo "alice: $@"
echo "$0 $1 $2 $3 $4"
echo "$# arguments"
echo "$*"
執行 alice.sh
shell> sh alice.sh in wonderland

# 以下為輸出結果:
alice: in wonderland
alice.sh in wonderland
2 arguments
in wonderland

另外,除了在執行程式時使用 Position Parameter 的功能外,也可以在 function 中使用喔! 以下舉個簡單例子:
#!/bin/bash

alice() {
echo "alice: $@"
echo "$0 $1 $2 $3 $4"
echo "$# arguments"
echo "$*"
}

alice in wonderland
此時直接執行程是不需帶參數:(結果跟上面是相同的喔!)
shell> sh alice.sh


Variable 有效範圍

在 variable 的有效範圍這個部分,shell script 與一般的程式語言不太一樣,在 function 中所定義的 variable 是 global 的! 而非 local 的喔!

這邊直接以範例來解釋! 請注意 $var1 囉!
#!/bin/bash

myFunc() {
echo "in function: $0 $1 $2"
var1="in function"
echo "var1: $var1"
}

var1="outside function"
echo "var1: $var1"
echo "$0: $1 $2"

myFunc funcArg1 funcArg2

echo "var1: $var1"
echo "$0: $1 $2"
接著執行程式囉!
shell> sh var_scope.sh arg1 arg2

# 以下為執行結果:
var1: outside function
var_scope.sh: arg1 arg2
in function: var_scope.sh funcArg1 funcArg2
var1: in function
var1: in function # 注意此行! $var1 的值被 function 改變囉!
var_scope.sh: arg1 arg2 # position parameter 不會被 function 影響到!


可能此時有人會問,script 要如何撰寫,才能讓 function 中的變數不會影響到 function 外面的變數呢? 其實很簡單,只要透過關鍵字「local」即可,如果將上面程式中的 function 改為以下內容:
myFunc() {
local var1 # 將變數加上了 local 關鍵字
echo "in function: $0 $1 $2"
var1="in function"
echo "var1: $var1"
}
出來的結果就會跟一般的程式語言相同的,結果如下:
shell> sh var_scope.sh arg1 arg2

# 以下為執行結果:
var1: outside function
var_scope.sh: arg1 arg2
in function: var_scope.sh funcArg1 funcArg2
var1: in function
var1: outside function # 果然 script 中的變數沒被 function 所影響到
var_scope.sh: arg1 arg2
以下用兩張圖來說明使用「local」關鍵字後,變數範圍的差異:
未用 local 變數
使用 local 變數後


最後,大家都知道要使用變數,必須在變數名稱前加上符號「$」,但假設有一個變數的名稱為 TEST,然後要在螢幕上輸出變數內容,在加一條底線,但如果使用以下方式:
echo $TEST_
這時系統會去判斷是否有名稱為「TEST_」的變數,結果當然是沒有,所以會輸出空白! 而為了得到正確的結果,可以在變數名稱旁邊加上左右大括號「{}」,所以只要改成以下語法就正常了:
echo ${TEST}_

4 則留言:

  1. useful, good job!
    ---
    typo,
    倒數第二段 第一行的最後一個字,
    "在"加一條底線 => "再"

    回覆刪除
  2. 非常實用,讚一個

    回覆刪除
  3. 很久了再回來看 還是很有價值

    回覆刪除
  4. 一個每天上班都被老闆罵的人2021年6月26日 晚上11:08

    $@ 與 $* 還是有差異的
    以下面兩篇文章解釋的來看
    https://stackoverflow.com/questions/12314451/accessing-bash-command-line-args-vs
    https://wiki.bash-hackers.org/scripting/posparams "$1c$2c$3c…c${N}"

    如果你是 $* $@ 那沒什麼差異,但如果你是使用 "$@" "$*" 那麼在解析的時候會有差異

    回覆刪除