函數:function
把一段獨立功能的代碼當做一個整體,而后為之取一個名字,命令的代碼段,即為函數。
注意:
定義函數的代碼段不會自動執行,在調用時執行;所謂調用函數,在代碼中給定函數名即可
函數名出現的任何位置,在代碼執行時,都會被自動替換為函數代碼;
過程式編程語言:代碼重用即可用到函數
模塊化編程
結構化編程
函數使用語法:
語法一:
function f_name{
..函數體
}
語法二:
f_name() {
…函數代碼(函數體)
}
函數的生命周期:
每次被調用時創建,返回時終止;
其狀態返回結果為函數體中運行的最后一條命令的狀態結果
自定義狀態返回值,需要使用:return
return:[0-255]
0:成功
1-255:失敗
示例:給定一個用戶名:取得用戶的ID號和默認shell
#!/bin/bash # userinfo() { if id "$username" &> /dev/null;then grep "^$username\>" /etc/passwd | cut -d: -f3,7 else echo "no such user" fi } username=$1 userinfo
示例2:服務腳本框架
#!/bin/bash #模擬創建文件來模擬服務的啟動、停止、重啟、狀態等。 prog=$(basename $0) //將此此腳本文件名當做創建的文件 lockfile=/var/lock/subsys/$prog //函數調用來將腳本文件名創建到/var/lock/subsys/下 ######定義函數、創建文件模擬啟動服務############### start(){ if [ -f $lockfile ];then echo "$prog is running yet" else touch $lockfile [ $? -eq 0 ] && echo "start $prog finshed" fi } ######定義函數、刪除文件模擬停止服務############### stop(){ if [ -f $lockfile ];then rm -f $lockfile [ $? -eq 0 ] && echo "stop $prog finished" else echo "$prog is not running" fi } ######定義函數、刪除文件在創建文件模擬重啟服務####### restart (){ if [ -f $lockfile ];then rm -f $lockfile touch $lockfile echo "restart $prog finished" else touch -f $lockfile echo "restart $prog finnished" fi } ######定義函數、查看文件模擬查看服務狀態############### status() { if [ -f $lockfile ];then echo "$prog is running" else echo "$prog is stopped" fi } #######定義函數、指定使用方法使用方法########## usage() { echo "Usage: $prog {start|stop|restart|startus}" } ######用case多分支條件語句來進行函數調用######### case $1 in //$1為用戶運行此腳本指定參數來進行調用函數。 start) //如果傳遞參數為start,則調用相對應的start函數。 start ;; stop) stop ;; restart) stop start ;; status) status ;; *) usage exit 1 ;; esac
函數的返回值:
函數的執行結果返回值
函數名出現的地方能夠顯示代碼執行結果
(1)使用echo或printf命令進行輸出
(2)函數體中調用的命令的執行結果
函數的退出狀態碼:
(1)默認取決于函數體中執行的最后一條命令的退出狀態碼
(2)自定義:return
函數可以接受參數
傳遞參數給函數時,在函數體中,可以使用$1,$2,…..,引用傳遞給函數的參數;還可以使用$*、$@引用所有參數,$#引用傳遞的參數的個數
在調用函數時,在函數名后面可以以空白符分割給定參數列表即可,列如,testfunc arg1 arg2 arg3…. (注意,testfunc 是函數名,arg1 arg2 arg3 是調用函數是傳遞參數)
示例:添加10個用戶
添加用戶的功能使用函數實現,用戶名做為參數傳遞給函數
#!/bin/bash # #5:user exists //說明5代表的含義 #####定義函數,功能:創建用戶########### addusers() { if id $1 &> /dev/null;then return 5 //如果if判斷語句為假,則表示用戶存在則不創建,并指定函數返回值為5 else useradd $1 retval=$? //創建用戶成功時將返回值保存到變量中,然后在用return命令返回其值。 return $retval //注意,如果不用變量保存其返回值,則在下方調用時不能更準確的判定其是否成功。因為狀態返回值是其上一條代碼的執行結果返回值。 fi } ######使用for循環語句來循環創建用戶################# for i in {1..10};do addusers ${1}${i} //調用函數,創建指定參數的用戶1到10, retval=$? //保存指定的函數值 if [ $retval -eq 0 ];then //判斷其返回值來輸出創建狀態,如果為0,則表示創建成功 echo "Add user ${1}${i} finished" elif [ $retval -eq 5 ];then //判斷其返回值來輸出創建狀態,如果為5,則表示其用戶存在,在函數體中,我們自己定義了用戶存在的函數返回值,如果用戶存在,則不會執行創建命令,也就不會生成返回值為0,所以其狀態返回值只賦值過一次,就是用戶存在時的返回值。 echo "user exist" else echo "Unkown Error" fi done
復習
變量作用域:
函數為代碼引入了一個獨立新的作用域,在函數內部存在,有效作用范圍只在函數內部。
局部變量:
作用域是函數的生命周期,在函數結束時被自動銷毀
定義局部變量的方法:local VAR=VALUE
本地變量:
作用域是腳本的聲明周期;
作用域是運行腳本的shell進程的生命周期。如果沒有在腳本中銷毀,則腳本的shell進程結束則變量銷毀
示例:本地變量和局部變量的區別
[root@CentOs6 tmp]# vim BianLiang.sh #!/bin/bash # name=tom //腳本內有個name變量,其值為tom setname() { // 定義函數 local name=jerry //定義于其腳本變量相同名的變量,其值為jerry,其中local為定義為局部變量。 #設置局部變量之后,此函數內的變量不會影響到調用它的腳本中的變量。 echo "Function: $name" //輸出函數內name變量值 } setname //調用函數 echo "shell:$name" 輸出name變量值,下面觀察一下效果 #############運行腳本,此時函數輸出變量和腳本輸出變量各為其自有的,因為我們把函數體內的變量設置為了局部變量,局部變量作用范圍為其函數體代碼段。############ [root@CentOs6 tmp]# bash BianLiang.sh Function: jerry shell:tom 將函數體內的local去掉 #############運行腳本,此時函數輸出變量和腳本輸出變量為相同,因為現在函數體內的變量為本地變量,即會影響到當前shell及其腳本中的變量,因為此時函數體內的內容替換到調用的位置之后就相當于再一次為給其相同名的變量(name)重新賦值,所有輸出結果為相同(當然這也跟輸出變量的位置有關)############ [root@CentOs6 tmp]# bash BianLiang.sh Function: jerry shell:jerry
函數遞歸:
函數直接或間接調用自身
示例:
階乘:10的階乘
10!=10*9!=10*9*8!=10*9*8*7!=…..
n!=n*(n-1)!=n*(n-1)*(n-2)!=……
10!=10*(10-1)!=10*(10-1)*(10-2)=….
[root@CentOs6 tmp]# cat JieChen.sh #!/bin/bash # fact () { if [ $1 -eq 0 -o $1 -eq 1 ];then echo 1 else echo $[$1*$(fact $[$1-1])] fi } fact $1
斐波切數列:
1.1.2.3.5.8.13.21….n-1+n-2
$[$(fab $[$1-1])+$(fab $[$1-2])]
#!/bin/bash # fab () { if [ $1 -eq 1 ];then echo 1 elif [ $1 -eq 2 ];then echo 1 else echo $[$(fab $[$1-1])+$(fab $[$1-2])] fi } for i in `seq 1 $1`;do fab $i done
原創文章,作者:Lii,如若轉載,請注明出處:http://www.www58058.com/38162
函數通過先定義,然后通過函數名來進行調用,同時他實現了代碼重用和效率提高,這是一個很重要的shell編程思想,需要多寫,多練。