站長新書 站長開講 首頁 最新文章 站長著作及審校 FreeBSD 筆記 Linux 筆記 Windows 筆記 虛擬化筆記 網管人雜誌 遊山玩水 關於本站
站長新書 VMware vSphere ICM 團購開跑了!!

Shell 函數

定義一個 Shell 函數

想在 Shell 內定義函數該如何宣告呢? 跟其它程式語言的宣告方式一樣語法如下

 function_name(option) {
       command....
 }

例如自定一個簡單的 echo function

 myecho(){                    //自定函數
    echo "function test"
 }
 
 myecho                       //呼叫函數 (畫面將顯示 function test)
 unset myecho                 //取消定義的 myecho 函數
 myecho                       //再次呼叫函數(因已取消所以系統找不到函數)

跳離函數【return】

在執行函數期間若想跳離函數可以使用 return 來跳離執行中的函數

 myecho(){                    //自定函數
    echo "function test 1"
    return                    
    echo "function test 2"
 }
 myecho                       //呼叫函數(僅顯示 function test 1)

上例 return 也可寫為 return 0 (0 為終止碼,執行成功也是傳回 0),若執行錯誤則是回傳 1 ~ 255 之間的數值,若省略的話則參考上一個執行指令傳回的終止碼來決定。

傳送多個 option 給函數【$#、$1、$2...】

函數的 option 只能傳送一個嗎? 當然不是那如果要傳送多個 option 該如何呼叫?

 myecho(){
    echo "option number:$#"   //$# 為查詢共有幾個 option
    echo "First option:$1"    //$1 為呼叫 option1
    echo "Second option:$2"   //$2 為呼叫 option2
    echo "Third:$3"           //$3 為呼叫 option3
    echo "------------------"
 }
 myecho Red                   //呼叫 myecho 函數並給予一個 option 名稱為 Red
 myecho Red Green
 myecho Red Green Yellow

執行結果

 option number:1
 First option:Red
 Second option:
 Third:
 ------------------
 option number:2
 First option:Red
 Second option:Green
 Third:
 ------------------
 option number:3
 First option:Red
 Second option:Green
 Third:Yellow
 ------------------

宣告函數內的區域變數【local】

被定義為區域變數的變數,當函數執行完後就隨著函數執行結束而回到原先定義的值,用例子來講比較容易了解

沒有宣告區域變數時

 1 osname(){
 2  name=`uname -rs`
 3  echo "OS name: $name"
 4 }
 5 name=`whoami`              //此時 name 為 user account
 6 osname                     //此時 name 為 FreeBSD 6.0-RELEASE 
 7 echo "user name: $name"    //此時 name 為 FreeBSD 6.0-RELEASE

執行結果為

 OS name: FreeBSD 6.0-RELEASE
 user name: FreeBSD 6.0-RELEASE     //why??

為何 user name 不是顯示使用者帳號而是顯示系統版本呢? 流程大概是這樣

 程式執行到第 5 行時把使用者帳號給寫入 name 
 程式執行到第 6 行時執行函數 osname 此時 name 的值又被寫成 uname -rs,因此輸出第 3 行的結果沒錯
 程式執行到第 7 行時因無宣告區域變數所以此時 name 的值並沒有因函數執行結束而清空還停留在 uname -rs 的結果

有宣告區域變數時

 1 osname(){
 2   local name   
 3  name=`uname -rs`
 4  echo "OS name: $name"
 5 }
 6 name=`whoami`              //此時 name 為 user account
 7 osname                     //此時 name 為 FreeBSD 6.0-RELEASE 
 8 echo "user name: $name"    //此時 name 為 user account (因為函數內的 name 已經因為函數結束而結束) 

執行結果為

 OS name: FreeBSD 6.0-RELEASE
 user name: weithenn

跨檔案呼叫函數【source or .(句點) filename】

由 Bourne shell 衍生者(包括 rc)用 "." 這個指令,由 C shell 衍生者則使用 "source"。我們把常用到的函數寫在一個固定的檔案內,當需要這函數的功能時再呼叫出來使用,這樣可讓 script 看起來更簡潔

首先寫一個叫 today.sh 內有函數 today

 #!/bin/sh
 today(){
 todayis=`date +%Y-%m-%d`
 }

之後 check.sh 欲使用函數 today 的功能

 #!/bin/sh
 todayis=                   //定義 todayis 變數(重要觀念!!)
 . ~/today.sh               //呼叫 today.sh 檔案
 today                      //呼叫 today 函數
 echo "Today is: $todayis"  

順利的話將會顯示今天的日期,必須要注意使用 today 函數時我一開始並沒有定義 todayis 變數(以為呼叫檔案呼叫函數就可直接使用裡面的變數了=.=a).經過 Clive 長輩指點後又修正了一下觀念以下是跟 Clive 長輩請教內容

 weithenn:說:
 當我 sh 1.sh 只會顯示說  Today is:
 evil[c] 說: 
 我多加了一行
 todayis=
 weithenn:說:
 so~~所以不只是呼叫函數還要在這個 script 去定義那個變數就對了
 evil[c] 說:
 本來就要先 declare ...
 weithenn:說:
 還以為呼叫函數就可開始用了
 evil[c] 說:
 只是大部份的 scripting language 都不要求
 evil[c] 說:
 java 就直接 compile error 給你看了
Go To Oddmuse OrgGo To FreeBSD OrgCreative Commons 2.5 Taiwansitestates.com