linux 腳本 之 函數篇
1 概述
函數function是由若幹條shell命令組成的語句塊,實現代碼重用和模塊化編程
函數只能作為shell程序的一部分存在。屬於shell的一段代碼,函數不是子進程。本身是腳本進程中的一部分,
所以函數裏的變量可以傳給調用該函數的腳本使用。默認情況下,這裏函數和shell的id是平級的關系,在函數的命令和shell是在同一pid下執行命令
它與shell程序形式上是相似的,不同的是它不是一個單獨的進程,不能獨立運行,而是shell程序的一部分
函數和shell程序比較相似,區別在於:
Shell程序在子Shell中運行
而Shell函數在當前Shell中運行。因此在當前Shell中,函數可以對shell中變量進行修改
2 定義函數
函數由兩部分組成:函數名和函數體
help function
語法一:
f_name(){ ...函數體... }
語法二:
function f_name{ ...函數體... }
語法三:
function f_name(){ ...函數體... }
3 函數使用
函數的定義和使用:
可在交互式環境下定義函數
可將函數放在腳本文件中作為它的一部分
可放在只包含函數的單獨文件中
調用:函數只有被調用才會執行
調用:給定函數名
函數名出現的地方,會被自動替換為函數代碼
函數的生命周期:被調用時創建,返回時終止
4 函數返回值
函數有兩種返回值:
函數的執行結果返回值:
(1) 使用echo等命令進行輸出
(2) 函數體中調用命令的輸出結果
函數的退出狀態碼:
(1) 默認取決於函數中執行的最後一條命令的退出狀態碼
(2) 自定義退出狀態碼,其格式為:
return 從函數中返回,用最後狀態命令決定返回值
return 0 無錯誤返回。
return 1-255 有錯誤返回
交互式環境下定義和使用函數
示例:
dir() { > ls-l > }
定義該函數後,若在$後面鍵入dir,其顯示結果同ls-l的作用相同
dir
該dir函數將一直保留到用戶從系統退出,或執行了如下所示的unset命令:
unset dir
5 在腳本中定義及使用函數
函數在使用前必須定義,因此應將函數定義放在腳本開始部分,直至shell首次發現它後才能使用
調用函數僅使用其函數名即可
6 使用函數文件
可以將經常使用的函數存入函數文件,然後將函數文件載入shell
文件名可任意選取,但最好與相關任務有某種聯系。例如:functions.main
一旦函數文件載入shell,就可以在命令行或腳本中調用函數。可以使用set命令查看所有定義的函數,其輸出列表包括已經載入shell的所有函數
若要改動函數,首先用unset命令從shell中刪除函數。改動完畢後,再重新載入此文件
創建函數文件
函數文件示例:
cat functions.main #!/bin/bash #functions.main findit() { if [ $# -lt 1 ] ; then echo "Usage:findit file" return 1 fi find / -name $1 –print }
7 載入函數
函數文件已創建好後,要將它載入shell
定位函數文件並載入shell的格式:
. filename 或source filename
註意:此即<點> <空格> <文件名>
這裏的文件名要帶正確路徑
示例:
上例中的函數,可使用如下命令:
. functions.main
檢查載入函數
使用set命令檢查函數是否已載入。set命令將在shell中顯示所有的載入函數
set | grep 函數名
如果有結果,表示該函數已經載入
8 執行shell函數
要執行函數,簡單地鍵入函數名即可
示例:
findit groups
/usr/bin/groups
/usr/local/backups/groups.bak
刪除shell函數
現在對函數做一些改動後,需要先刪除函數,使其對shell不可用。使用unset命令完成刪除函數
命令格式為:
unset function_name
示例:
unset findit
再鍵入set命令,函數將不再顯示
9 環境函數
使子進程也可使用
聲明:export -f function_name
查看:export -f 或declare -xf
10 函數參數
函數可以接受參數:
傳遞參數給函數:調用函數時,在函數名後面以空白分隔給定參數列表即可;例如“testfunc arg1 arg2 ...”
在函數體中當中,可使用$1, $2, ...調用這些參數;還可以使用[email protected], $*, $#等特殊變量
環境變量由父進程傳給子進程,不能從子進程傳給父進程
可以將常用的功能寫出函數塊,放到統一的文件裏,後續要調用就直接用調用該函數文件就可以直接用著函數
腳本內容如下,當腳本中函數的$1 等參數是腳本的位置變量,但是一旦在函數後面跟得變量值,就是函數的位置參數。
$0特殊,$0特殊腳本的名稱,在函數中也是所運行的腳本的名稱不是函數名
testvar () { while [ $# -gt 0 ];do echo "\$1 is func $1,\$0 is $0,\$# is $#" shift done } testvar $1 $2 testvar ab cd ef
11 函數變量
變量作用域:
環境變量:當前shell和子shell有效
本地變量:只在當前shell進程有效,為執行腳本會啟動專用子shell進程;因此,本地變量的作用範圍是當前shell腳本程序文件,包括腳本中的函數
局部變量:函數的生命周期;函數結束時變量被自動銷毀
註意:如果函數中有局部變量,如果其名稱同本地變量,使用局部變量
在函數中定義局部變量的方法
local NAME=VALUE
通過以下實驗來測試本地變量
通過調整邏輯與&&前面的語句的執行結果的真假,來觀察RC1或者RC2的賦值情況
通過local這個關鍵字,來查看RC1或者RC2被賦予的值是否會傳到函數外面,觀察函數本地變量的區別
pwd && local RC1=$ || local RC2=$? ?
則調用腳本的時候,函數外面的RC1為空值,因為local的變量只作用於函數內
pwd && RC1=$? || RC2=$?
則調用腳本的時候,函數外面的RC1有值,為前面語句的執行結果,本例子中為0值
腳本如下
test_local () { #pwdsss && RC1=$? || RC2=$? pwd && local RC1=$ || local RC2=$? ? } test_local echo RC1=$RC1 echo RC2=$RC2
11 函數遞歸
函數遞歸:
函數直接或間接調用自身,遞歸會將上一次運算的結果全部帶入下一次的計算
註意遞歸層數
遞歸實例:
階乘是基斯頓·卡曼於1808 年發明的運算符號,是數學術語
一個正整數的階乘(factorial)是所有小於及等於該數的正整數的積,並且有0的階乘為1,自然數n的階乘寫作n!
n!=1×2×3×...×n
階乘亦可以遞歸方式定義:0!=1,n!=(n-1)!×n
n!=n(n-1)(n-2)...1
n(n-1)! = n(n-1)(n-2)!
函數遞歸示例
示例:fact.sh
#!/bin/bash # fact() { if [ $1 -eq 0 -o $1 -eq 1 ]; then echo 1 else echo $[$1*$(fact $[$1-1])] fi } fact $1
12 fork炸彈
fork炸彈是一種惡意程序,它的內部是一個不斷在fork進程的無限循環,實質是一個簡單的遞歸程序。
由於程序是遞歸的,如果沒有任何限制,這會導致這個簡單的程序迅速耗盡系統裏面的所有資源
函數實現
:(){ :|:& };:
bomb() { bomb | bomb & }; bomb
腳本實現
cat Bomb.sh
#!/bin/bash
./$0|./$0&
例子
bomb(){ bomb|bomb& } echo "$0 is danger,it will make your computer resource exhaustedin a few seconds,your computer need restart after that" read -p "Please input your choice,y or n: " choice case $choice in y) bomb ;; n) echo "You make a good chioce" exit 6 ;; *) echo "Your input is wrong" exit 8 ;; esac
13 總結
以上介紹了函數的定義,調用,返回值,取消函數,變量,遞歸等方面進行了介紹。希望對使讀者再使用函數時有所幫助
本文出自 “自學linux” 博客,請務必保留此出處http://ghbsunny.blog.51cto.com/7759574/1962919
linux 腳本 之 函數篇