1. 程式人生 > >bash腳本之函數簡單介紹、應用及函數的簡單遞歸調用

bash腳本之函數簡單介紹、應用及函數的簡單遞歸調用

bash腳本

bash腳本編程--函數

在bash中,函數是由命令和語句結構構成的能夠實現特定功能的集合;


為什麽要在bash中引入函數?

在bash腳本編寫過程中有可能會出現重復且不做任何改變的代碼內容,如果這類內容全靠原始代碼書寫的話不易於排錯和優化;因此我們可以選擇將此類代碼封裝在函數中,在適當的場景中可以重復調用執行;


像此類被封裝起來的代碼塊通常稱其為模塊,也叫函數;


註意:

1.想要使用函數,必須在使用前先定義出來;

2.如果在某個bash腳本中包含了函數體,默認函數體中的各命令和語句不會執行的;只有在調用函數名的時候,才會執行函數體中的命令和語句;

3.通常需要重復執行的代碼塊或命令集,可以封裝成函數;

4.被調用的函數只能在調用的函數的shell中被執行;


定義函數的方法:

函數有兩部分組成:

函數名+函數體


函數名:調用函數時所使用的字符串標識;在一個執行環境中,函數名是不允許重復定義的;

函數體:能夠實現特定獨立功能的shell命令或結構化語句塊;


定義的語法結構:

語法一:

function func_name {

func_body

}

語法二:

func_name() {

func_body

}

註意:在語法二的格式中,func_name和()之間絕對不能有空白字符存在;


註意:函數可以在腳本中被定義,也可以在當前shell中通過交互式環境定義;



函數的使用方法:

函數在定義的時候,其函數體中包含的所有命令或結構化語句都不會被執行;只有在函數被調用時,才能執行其函數體中的各命令和語句;


調用方式:在命令行腳本中,通過直接給出的函數名的方式進行函數調用;


通常可以將常用的函數存放在專門用於保存函數的文件中,如果想要調用這個文件中已經被定義保存的函數,只需要在命令行或腳本中,使用source命令(.命令)加載文件內容到當前shell中,然後在直接使用函數名調用函數即可;


函數的撤銷:

unset命令

格式:# unset func_name


註意:可以使用set命令查看當前已經定義並生效的函數;


函數的返回值:

兩種返回值:

函數的執行結果返回值:

1.在函數體中所添加的命令有標準輸出;

2.在函數體中使用echo或printf命令強制輸出返回信息;


函數的執行狀態返回值:

1.默認情況下其狀態返回值為函數體中最後一條命令的狀態返回值;

2.自定義狀態返回值或者叫做退出碼;

return命令:

return: return [n]

從一個 shell 函數返回


n:0-255(1,2,127為系統保留的狀態碼,盡量不用)

0:表示無錯誤返回

1-255:表示有錯誤返回;

註意:在函數被調用執行時,一旦遇到return命令則不會再繼續執行函數體中其他的後續命令,立刻結束此次函數的調用執行;



函數的生命周期:

一般來講,從函數被調用時開始,知道函數體中所有的命令和結構化語句全部執行完成或遇到return命令,函數的調用結束;


函數的實參:

對應的bash函數來說,沒有形參,只有實參;

bash函數的實參是使用$1,$2...位置變量來提供數據的;


func_name pos1 pos2 ...


可以使用$@或者$*表示全部的參數列表;

可以使用$#計算參數的個數;


註意:為函數提供參數時使用的位置變量,是調用函數名時在函數名後面的對用位置上的參數信息;與腳本的位置參數不是一回事;


變量:

函數被調用時,必須在某特定的shell中被調用,因此,函數中可以繼承並識別出環境變量和由調用函數shell定義的本地變量;


在函數中還可以定義局部變量;而局部變量僅在函數的生命周期內有效;在結束函數執行之前,應該撤銷所有該函數定義的局部變量;


局部變量的定義方法:

local VAR_NAME=VALUE


變量的替換方式:

前提:定義環境變量:

export MYVAR=qhdlink


示例:

#!/bin/bash

#區別全局變量、本地變量、局部變量;

testvar() {

#local命令定義局部變量,只在局部有效;

local MYVAR=chinalink

echo "Internal function: $MYVAR"

}

#全局變量

echo "Global variables: $MYVAR"

MYVAR=link

#本地變量

echo "External function, $MYVAR"

#調用局部變量

testvar




函數的遞歸調用:

廣義:在一個函數中調用另一個函數

狹義:在函數體中調用函數自身;

直接調用:

func1(){

func1

}

間接調用:

func2(){

func1

}


func1(){

func2

}



函數的直接遞歸調用示例1:

計算某個數字的階乘:

利用for循環:

#!/bin/bash

#本腳本計算某個數字的階乘:

#定義fact為1;

fact=1

#如果給定的數字等於0,就輸出0的階乘為$fact為1,如果數字等於1就輸出1的階乘為$fact為1,否則就開始計算輸入數字的階乘;

if [ $1 -eq 0 ] ; then

echo "0! is $fact"

elif [ $1 -eq 1 ] ; then

echo "1! is $fact"

else

#利用for循環計算階乘,從1開始一直到$1;

for I in $(seq $1) ; do

#階乘是n!=1×2×3×...×n,所以$1的階乘是$1!=1×2×3×...×$1;

let fact=$[fact*$I]

done

echo "${1}! is $fact"

fi

#回收變量;

unset fact I


利用函數遞歸調用:

#!/bin/bash

#本腳本利用函數計算某個數字的階乘:

#定義函數fact;

fact(){

#如果給定的數字等於0或1就執行顯示數字的階乘等於1,否則就利用函數計算給定數字為非0非1的階乘;

if [ $1 -eq 0 ] || [ $1 -eq 1 ] ; then

echo 1

else

#用$1減去$($1-1)的階乘,n的階乘就是nx(n-1)!的階乘,n-1的階乘就是(n-1)x(n-2)!的階乘,依次類推;

echo "$[$1*$(fact $[$1-1])]"

fi

}


echo "${1}! is $(fact $1)"



函數的直接遞歸調用示例2:

斐波那波數列(黃金分割數列)

1 1 2 3 5 8 13 21 34 55 ...

#!/bin/bash

#本腳本顯示斐波那波數列(黃金分割數列);

#定義函數fabonacci;

fabonacci(){

#如果給定的數字為1或者2就顯示數列1,否則就利用函數計算給定數字為非1非2的黃金分割數;

if [ $1 -eq 1 ] || [ $1 -eq 2 ] ; then

echo -n "1 "

else

#函數的式子來自黃金分割數列的規律,利用函數的自我調用來計算顯示黃金分割數,給定數字的黃金分割數列規律是:給定數字等於給定數字在數列中的前兩個數字之和即如下規律;

echo -n "$[$(fabonacci $[$1-1])+$(fabonacci $[$1-2])] "

fi

}


for I in $(seq $1) ; do

fabonacci $I

done

echo


函數的直接遞歸調用示例3:

漢諾塔

#!/bin/bash

#本腳本顯示給出漢諾塔層數的搬運次數;

#定義步數step為0;

step=0

#定義函數move為挪動盤子的方法:這裏簡化利用最簡單的只有一個盤子的時候,先把盤子挪動到第二個柱子,再把盤子從第二個柱子挪動到第三個盤子;

move(){

#隨著盤子的挪動,步數也要進行增長;

let step++

#先把盤子挪動到第二個柱子,再把盤子從第二個柱子挪動到第三個盤子;

echo "$step: move disk $1 $2 --> $3"

}

#定義函數hanoi為移動規律;

hanoi(){

#當塔為1層時,直接先把盤子挪動到第二個柱子,再把盤子從第二個柱子挪動到第三個盤子,否則利用漢諾塔規律和函數的自我調用實現多層數的步數計算;

if [ $1 -eq 1 ] ; then

move $1 $2 $4

else

#除了塔底層最後一個大盤子,將其他的盤子整合到一起由第一個柱子整體挪動到第二個柱子,再將底層的最後一個大盤子挪到第三個柱子,再將第二個柱子上的其他盤子整合挪到第三個柱子:用hanoi挪到兩次,再用move挪一次,再使用調用hanoi函數完成最後的把其他盤子整體由第二個柱子移動到第三個柱子;

hanoi "$[$1-1]" $2 $4 $3

move $1 $2 $4

hanoi "$[$1-1]" $3 $2 $4

fi

}

#傳遞四個參數:層數,A柱,B柱,C柱;

hanoi $1 A B C


#回收變量

unset step A B C


bash腳本之函數簡單介紹、應用及函數的簡單遞歸調用