標籤:function
function —— 函數
把那些在指令碼中重複出現並且沒有任何改變的代碼,封裝起來,在適當的情境中調用執行;
程式員將這種被封裝起來的代碼稱為功能體,或者叫模組;
在shell指令碼編程中,函數是由若干條shell命令組成的語句塊;通常用於代碼重用和模組化封裝;
函數裡面的內容和shell程式形式上是一致的;不同之處就是,shell代碼可以直接被執行;而函數中的內容,不能獨立執行,只有被調用的時候才執行;
函數是在shell程式的當前shell中啟動並執行;
bash
bash script_file
function
定義函數:
函數是由兩部分組成:
函數名稱 + 函數體(能夠實現獨立功能的shell語句塊)
文法一:
function func_name {
函數體
}
文法二:
func_name() {
函數體
}
注意:函數名和()之間不能加空白字元;
注意:函數可以在互動式環境下定義,也可以在指令碼中定義;
函數的使用
函數在定義的時候,其函數體中包含的所有命令均不會被執行;只有函數被調用的時候,才會執行其中的命令語句;
調用方式:通過直接給出函數名稱的方式調用;
有很多的函數是存放於專門用於儲存函數的檔案中;如果想要調用這樣的檔案中儲存的函數,使用source命令(.)負載檔案,然後再以直接給出函數名稱的方式調用函數;
使用set命令可以查看所有當前shell中生效的函數;
使用unset命令可以撤銷已經定義的函數;
函數的傳回值:
兩種傳回值:
函數的執行結果的傳回值:
1.在函數體中使用了echo或printf命令輸出的結果;
2.在函數體中某些命令輸出的結果;
函數的狀態傳回值:
1.函數中最後一條命令的執行狀態傳回值;
2.自訂退出狀態代碼:
return [n]
n:0-255
注意:只要函數在執行時,遇到了return命令,不管函數中的命令語句是否全部執行完成,立刻退出函數;
函數的生命週期:
從被調用開始,到遇到return命令或全部的語句執行完成為止;
函數的實參
在函數體中,可以使用$1,$2,..位置變數為函數提供參數;還可以使用$*或[email protected]的方式引用所有位置參數;還可以使用$#計算為函數傳遞的參數個數;
在調用函數的時候,直接在函數名稱後面以空白字元分隔多個參數即可;比如:func_name arg1 arg2 ...
傳遞給函數參數的位置參數,是調用函數的時候,函數名稱後面的以空白字元分隔的字串序列;跟指令碼的位置參數不是一回事;
變數:
shell中的變數為弱變數
1.無需事先聲明
2.無需指定變數類型,預設為字元型
變數分類:
環境變數:
當前shell及子shell
本地變數:
當前shell
局部變數:
local VAR_NAME=VALUE
當前函數體
位置變數
特殊變數
手動撤銷自己定義或聲明的所有變數;
函數的遞迴調用
簡單來說,就是在函數體中調用函數自身;
階乘:
N!=N*(N-1)!=N*(N-1)*(N-2)!=...=N*(N-1)*(N-2)*...*2*1
#!/bin/bash
# Author: Tianyu.Zhao
#
fact(){
if [ $1 -eq 0 ] || [ $1 -eq 1 ] ; then
echo 1
else
echo "$[$1*$(fact $[$1-1])]"
fi
}
echo -n "$1!="
fact $1
例子: 斐波那契數列(黃金分隔數列):
1 1 2 3 5 8 13 21 34 55 ...
假設兔子出生一個月之後才會有繁殖能力:
N=N-1 + N-2
shell代碼:
#!/bin/bash
# Author: Tianyu.Zhao
#
fabonacci(){
if [ $1 -eq 1 ] ; then
echo 1
elif [ $1 -eq 2 ] ; then
echo 1
else
echo $[$(fabonacci $[$1-1])+$(fabonacci $[$1-2])]
fi
}
#列出所有的斐波那契數列的項
for I in `seq 0 $1` ; do
fabonacci $I
done
例子: 漢諾塔(又稱河內塔)問題是源於印度一個古老傳說。大梵天創造世界的時候做了三根金剛石砫子,在一根柱子上從下往上按照大小順序摞著64片黃金圓盤。大梵天命令婆羅門把圓盤從下面開始按大小順序重新擺放在另一根柱子上。並且規定,在小圓盤上不能放大圓盤,在三根柱子之間一次只能移動一個圓盤。
利用函數,實現N片盤的漢諾塔的移動步驟
#!/bin/bash
# Author: Tianyu.Zhao
#
step=0
move(){
let step++
echo "$step: move disk $1 $2 -----> $3"
}
hanoi(){
if [ $1 -eq 1 ];then
move $1 $2 $4
else
hanoi "$[$1-1]" $2 $4 $3
move $1 $2 $4
hanoi "$[$1-1]" $3 $2 $4
fi
}
hanoi $1 A B C
檔案abc.txt的內容如下:
2,3,4,5,6
B,c,d,e,f
6,7,8,9,10
f,g,h,i,j
寫一個指令碼,利用任一迴圈結構,輸出每一行的第二個和第四個字元(以逗號分隔)
回顧:
shell指令碼編程之函數
練習:
寫一個指令碼:
1.允許使用者通過命令列傳遞參數,實現使用者賬戶的管理;
2.如果給出-a|--add選項,就建立該選項後面的使用者賬戶;
3.如果給出-d|--del選項,就刪除該選項後面的使用者賬戶;
4.如果使用者給出-v|--verbose選項, 就顯示刪除或建立使用者的資訊;
5.如果使用者給出-h|--help選項,就顯示協助資訊,並且以0作為退出狀態代碼退出指令碼的運行;
6.如果使用者給出其他選項,顯示協助資訊,並以5作為退出狀態代碼鬼畜指令碼的運行;
#!/bin/bash
#Author: Link
#Description: administrate users
#5: no enough args
#6: error args
#
DEBUG=0
ADDUSER=0
DEUSER=0
usage(){
echo "Usage: $(basename $0) -a|--add user1,user2,... | -d|--del user1,user2,... | [-v|-verbose] | [-h|--help]"
echo
echo "Options: "
echo -e " -a, --add\vCreate user from list."
echo -e " -d, --del\vDelete user from list."
echo -e " -v, --verbose\vDisplay infomation for your operating."
echo -e " -h, --help\vDisplay this menu."
}
createuser() {
ADDUSER_LIST=$(echo $1 | tr ‘,‘ ‘ ‘)
for I in $ADDUSER_LIST ; do
if id $I &> /dev/null ; then
[ $DEBUG -eq 1 ] && echo "$I exists."
else
useradd $I &> /dev/null
echo $I | passwd --stdin $I &> /dev/null
[ $DEBUG -eq 1 ] && echo "Create $I successfully."
fi
done
}
deleteuser() {
DELUSER_LIST=$(echo $1 | tr ‘,‘ ‘ ‘)
for J in $DELUSER_LIST ; do
if id $J &> /dev/null ; then
userdel -r $J &> /dev/null
[ $DEBUG -eq 1 ] && echo "Delete $J finished."
else
[ $DEBUG -eq 1 ] && echo "$I not exists."
fi
done
}
if [ $# -le 0 ] ; then
usage
exit 5
fi
while [ $# -ne 0 ] ; do
case $1 in
-h|--help)
usage
exit
;;
-v|--verbose)
DEBUG=1
shift
;;
-a|--add)
ADDUSER=1
ALIST=$2
shift 2
;;
-d|--del)
DELUSER=1
DLIST=$2
shift 2
;;
*)
usage
exit 6
;;
esac
done
if [ $ADDUSER -eq 1 ] ; then
createuser $ALIST
fi
if [ $DELUSER -eq 1 ] ; then
deleteuser $DLIST
fi
Linux初學之函數