1. 程式人生 > 實用技巧 >九、Shell之函式

九、Shell之函式

一、shell的函式介紹

函式的作用就是將程式裡多次被呼叫的相同程式碼組合起來(函式體),併為其取一個名字(即函式名),其他所有想重複呼叫這部分程式碼的地方都只需要呼叫這個名字就可以了。當需要修改這部分重複程式碼時,只需要改變函式體內的一份程式碼即可實現對所有呼叫的修改,也可以把函式獨立地寫到檔案裡,當需要呼叫函式時,再載入進來使用。

使用Shell函式的優勢:

1、把相同的程式段定義成函式,可以減少整個程式的程式碼量,提升開發效率。 2、增加程式的可讀性、易讀性,提升管理效率。 3、可以實現程式功能模組化,使得程式具備通用性(可移植性)。

二、shell函式的格式及執行

1、函式的格式

方法一:
function 函式名(){ 指令集 return n } 方法二: 函式名(){ 指令集 return n }

2、函式的執行方法

1)執行不帶引數的函式

funcation 函式名(){
  指令集
  return n
}
函式名

重要說明:
1、執行Shell函式時,函式名前的function和函式後的小括號都不要帶。
2、函式的定義必須在要執行的程式前面定義或載入。
3、Shell執行系統中各種程式的執行順序為:系統別名→函式→系統命令→可執行檔案。
4、函式執行時,會和呼叫它的指令碼共用變數,也可以為函式設定區域性變數及特殊位置引數。
5、在Shell函式裡面,return命令的功能與exit類似,return的作用是退出函式,而exit是退出指令碼檔案。
6、return語句會返回一個退出值(即返回值)給呼叫函式的當前程式,而exit會返回一個退出值(即返回值)給執行程式的當前Shell。 7、如果將函式存放在獨立的檔案中,被指令碼載入使用時,需要使用source或“.”來載入。 8、在函式內一般使用local定義區域性變數,這些變數離開函式後就會消失。

2)帶引數的函式執行方法

funcation 函式名(){
  指令集
  return n
}
函式名 引數1 引數2

函式後接引數的說明:
1、Shell的位置引數($1、$2…、$#、$*、$?及$@)都可以作為函式的引數來使用。
2、此時父指令碼的引數臨時地被函式引數所掩蓋或隱藏。
3、$0比較特殊,它仍然是父指令碼的名稱。 4、當函式執行完成時,原來的命令列指令碼的引數即可恢復。 5、函式的引數變數是在函式體裡面定義的。

3、Shell函式的基礎案例

#! /bin/bash

function ywx() {
  echo ywx
}

king() {
  echo king
}

ywx   #呼叫ywx函式
king  #呼叫king函式

測試指令碼

[root@node1 scripts]# bash hanshu1.sh 
ywx
king

更改指令碼如下:

#! /bin/bash

function ywx() {
  echo ywx
}
ywx   
king  
#只定義ywx函式,不定一king函式

測試指令碼

[root@node1 scripts]# bash hanshu1.sh 
ywx
hanshu1.sh: line 9: king: command not found
#沒有定義的king函式會被認為是一個命令來執行,king命令不存在的

4、把函式與指令碼分離

在寫函式時,可以把函式寫在系統的函式檔案中(/etc/init.d/functions)。

在需要函式時,只需要載入該函式檔案,即可呼叫該檔案中的所有函式。

把hello_world函式新增到函式檔案中

[root@node1 scripts]#cat /etc/init.d/functions 
......省略
hello_world() {
  echo "ni hao world!!!"
}
#注意:函式需要載入下面內容的前面
# A sed expression to filter out the files that is_ignored_file recognizes
__sed_discard_ignored_files='/\(~\|\.bak\|\.old\|\.orig\|\.rpmnew\|\.rpmorig\|\.rpmsave\)$/d'

if [ "$_use_systemctl" = "1" ]; then
        if  [ "x$1" = xstart -o \
              "x$1" = xstop -o \
              "x$1" = xrestart -o \
              "x$1" = xreload -o \
              "x$1" = xtry-restart -o \
              "x$1" = xforce-reload -o \
              "x$1" = xcondrestart ] ; then

        systemctl_redirect $0 $1
        exit $?
    fi
fi

strstr "$(cat /proc/cmdline)" "rc.debug" && set -x
return 0

在指令碼中直接除錯函式檔案中的函式

#! /bin/bash
. /etc/init.d/functions  #在指令碼中呼叫函式檔案

hello_world   #呼叫函式檔案中的"hello_world函式"

測試指令碼

[root@node1 scripts]# bash hanshu2.sh 
ni hao world!!!

5、函式的傳參

案例1:

#! /bin/bash
hello_world() {
  echo "ni hao $1"
}

hello_world china  #呼叫函式後面緊跟的引數為定義函式時,其中的$1 

測試指令碼

[root@node1 scripts]# cat /scripts/hanshu3.sh 
#! /bin/bash
hello_world() {
  echo "ni hao $1"
}
hello_world china

[root@node1 scripts]# bash /scripts/hanshu3.sh 
ni hao china

案例2:

#! /bin/bash
hello_world() {
  echo "ni hao $1"
}

hello_world $1  #該處的$1為指令碼引數$1,把指令碼引數的$1傳遞給了函式裡面的$1

測試指令碼

[root@node1 scripts]# cat /scripts/hanshu4.sh 
#! /bin/bash

hello_world() {
  echo "ni hao $1"
}

hello_world $1

[root@node1 scripts]# bash hanshu4.sh chinese  #指令碼的$1引數傳遞給了函式中的$1
ni hao chinese

三、函式案例

使用函式編寫url的檢查

#! /bin/bash
#配置Usage函式
Usage() {
    echo "Usage $0 url"
}
#配置url_check函式
url_check() {
curl $1 &> /dev/null
#wget --spider -q -o /dev/null --tries=1 -T 5 $1   #curl的命令2選1即可
if [ $? -eq 0 ];then
   echo "$1 is running ok!"
else
   echo "$1 is false!"
fi
}

main() {
  if [ $# -ne 1 ];then
    Usage        #<==呼叫Usage函式
    exit 1
  fi
  url_check $1   #<==呼叫url_check函式,接收函式的傳參,即把下文main結尾的$*傳到這裡。
}

main $*          #<==這裡的$*就是把命令列接收的所有引數作為函式引數傳給函式內部,是一種常用手法。

測試指令碼

[root@node1 scripts]# sh url_check.sh www.baiduddd
www.baiduddd is false!
[root@node1 scripts]# sh url_check.sh www.baidu.com
www.baidu.com is running ok!
[root@node1 scripts]# sh url_check.sh www.baidu.com www.ywx.com
Usage url_check.sh url
 

引用/etc/init.d/functions函式檔案

#! /bin/bash
. /etc/init.d/functions    #引用functions檔案

#配置Usage函式
Usage() {
    echo "Usage $0 url"
}
#配置url_check函式
url_check() {
curl $1 &> /dev/null
#wget --spider -q -o /dev/null --tries=1 -T 5 $1   #curl的命令2選1即可
if [ $? -eq 0 ];then
   action "$1 is running ok!" /bin/true   #呼叫functions中的action函式
else 
   action "$1 is false!" /bin/false       #呼叫functions中的action函式
fi
}

main() {
  if [ $# -ne 1 ];then
    Usage        #<==呼叫Usage函式
    exit 1
  fi
  url_check $1   #<==呼叫url_check函式,接收函式的傳參,即把下文main結尾的$*傳到這裡。
}

main $*          #<==這裡的$*就是把命令列接收的所有引數作為函式引數傳給函式內部,是一種常用手法。

測試指令碼: