8月29日 腳本進階3 函數

1、函數和shell程序的區別

?Shell程序在子Shell中運行
?而Shell函數在當前Shell中運行。因此在當前Shell中,函數可以對shell中變量進行修改

[root@redhat7 script]#name=wang;func1 () { echo func1 is runing;echo $name;echo processid is $$; }
[root@redhat7 script]#func1
func1 is runing
wang
processid is 1410        ---函數是在當前shell中運行的,并沒有開子進程
[root@redhat7 script]#echo $$
1410
[root@redhat7 script]#name=wang;func1 () { name=mage;echo func1 is runing;echo $name;echo processid is $$; }
[root@redhat7 script]#func1
func1 is runing
mage  ---因為函數執行的時候沒有開子進程,所以會影響當前進程定義的變量,會對其進行修改。
processid is 1410
[root@redhat7 script]#echo $$
1410

2、查看定義的函數

[root@redhat7 script]#declare -f |grep -A 10 func1   ---declare -f可以查看所有定義的函數
func1 () 
{ 
    name=mage;
    echo func1 is runing;
    echo $name;
    echo processid is $$
}
[root@redhat7 ~]#declare -f func1 ---可以不用過濾直接查看定義的函數
func1 () 
{ 
    declare -i num=100;
    echo func1 is runing;
    echo "func1:num=$num"
}
[root@redhat7 script]#set |grep -A 10 func1---set可以查看所有定義的函數和變量
func1 () 
{ 
    name=mage;
    echo func1 is runing;
    echo $name;
    echo processid is $$
}

3、函數的組成部分

?函數由兩部分組成:函數名和函數體
?help function
?語法一:
function f_name{
...函數體...
}
?語法二: ---- 此種方法是最常用的,系統自帶的函數一般都是用這種方法定義的函數
function f_name(){
...函數體...
}
?語法三:
f_name(){
...函數體

4、別名對函數的影響

[root@redhat7 script]#declare -f |grep func1 -A 5   ---之前定義過一個這樣的函數
func1 () 
{ 
    name=mage;
    echo func1 is runing;
    echo $name;
    echo processid is $$
}
[root@redhat7 script]#alias func1='ls -l'     ---將函數名定義為別名
[root@redhat7 script]#func1   ----當調用這個函數時,執行的是別名而不是函數本身
total 168
-rwxr-xr-x. 1 root root  156 Aug 24 18:59 192.sh
-rwxr-xr-x. 1 root root  390 Aug 25 08:23 21dengyao.sh

總結:定義別名之后函數就無法被調用了,所以一般將函數寫到腳本里使用,因為腳本里面別名是不起作用的。

4、函數的使用

?可在交互式環境下定義函數
?可將函數放在腳本文件中作為它的一部分
?可放在只包含函數的單獨文件中
?調用:函數只有被調用才會執行
調用:給定函數名
函數名出現的地方,會被自動替換為函數代碼
?函數的生命周期:被調用時創建,返回時終止

5、函數的退出狀態碼

(1) 默認取決于函數中執行的最后一條命令的退出狀態碼
(2) 自定義退出狀態碼,其格式為:
return 從函數中返回,用最后狀態命令決定返回值,退出函數不可以用exit,exit會退出整個腳本,用return可以退出函數。
return 0 無錯誤返回。
return 1-255 有錯誤返回
函數和腳本的退出狀態碼保存到$?里
unset 函數名可以銷毀函數和撤銷變量的操作一樣
set -- 銷毀位置變量

6、在腳本中定義使用函數

?函數在使用前必須定義,因此應將函數定義放在腳本開始部分,直至shell首次發現它后才能使用
?調用函數僅使用其函數名即可
示例

[root@redhat7 script]#vim func1.sh 
#!/bin/bash
#
hello () {
        echo "Hello there today's date is `date +%F`"
}
echo "now going to function hello"
hello    ---要調用這個函數,使用函數名就可以
echo "back from the function"
[root@redhat7 script]#./func1.sh 
now going to function hello
Hello there today's date is 2017-08-29
back from the function

7、使用函數文件

[root@redhat7 script]#vim funcs   ----創建一個函數文件,注意函數文
件不是腳本,不用加#!/bin/bash
hello () {
        echo "Hello there today's date is `date +%F`"
 [root@redhat7 script]#vim func1.sh 
#!/bin/bash
#
source funcs    ---先把函數文件載入到當前的腳本中,也可以用
. funcs,注意中間要有空格
echo "now going to function hello"
hello     ----然后調用這個函數
echo "back from the function"
[root@redhat7 script]#vim functions 
hello () {
        echo "Hello there today's date is `date +%F`"
}
add () {
       echo $[$1+$2]
}
osversion () {
            sed -r 's/.* ([0-9])\..*/\1/' /etc/redhat-release ---定義一個函
數,判斷版本號
}
[root@redhat7 script]#. functions 
[root@redhat7 script]#osversion 
7
[root@redhat7 script]#[ `osversion` == 7 ]&&echo 7  ---調用這個函
數,進行判斷,如果是7,就打印7
7

注意:如果函數文件和腳本文件不在同一個目錄下,此時函數文件要寫上全路徑,比如source /root/funs。使用函數文件可以把經常使用的函數都放到一個函數文件里,使用的時候先載入這個函數文件,然后調用對應的函數就可以。

8、函數變量

?變量作用域:
環境變量:當前shell和子shell有效
本地變量:只在當前shell進程有效,為執行腳本會啟動專用子shell進程;因此,本地變量的作用范圍是當前shell腳本程序文件,包括腳本中的函數
?局部變量:函數的生命周期;函數結束時變量被自動銷毀,只對函數內的變量有效。
?在函數中定義局部變量的方法
local NAME=VALUE
示例

[root@redhat7 ~]#func1 () { local name=mage;echo func1 is runing;echo "func1:name=$name"; }
[root@redhat7 ~]#func1
func1 is runing
func1:name=mage
[root@redhat7 ~]#name=wang
[root@redhat7 ~]#echo $name    ---因為name在函數中被定義為局部
變量,只在函數中生效,所以不會影響當前shell中的變量
wang

總結:為了避免函數中的變量影響腳本中的其他變量,一般將函數中的變量定義為局部變量。

[root@redhat7 ~]#func1 () { declare -i num=100;echo func1 is runing;echo "func1:num=$num"; }  ---declare -i 作用是聲明是整數,
但放到函數中聲明是整數的同時,也將變量聲明為局部變量,不影響
當前shell的變量
[root@redhat7 ~]#num=200
[root@redhat7 ~]#func1
func1 is runing
func1:num=100
[root@redhat7 ~]#echo $num
200
[root@redhat7 ~]#func1 () { declare -ig num=100;echo func1 is runing;echo "func1:num=$num"; }   ----如果要將函數內的變量定義為
全局變量也就是本地變量,可以使用-g選項
[root@redhat7 ~]#num=300
[root@redhat7 ~]#func1
func1 is runing
func1:num=100
[root@redhat7 ~]#echo $num
100

9、環境函數

[root@redhat7 script]#vim func1.sh 
#!/bin/bash
#
hello  ---調用hello這個函數
[root@redhat7 script]#source /root/funcs ---先把用hello函數的funcs函數文件載入到當前shell中
[root@redhat7 script]#hello  ---在當前shell中調用這個函數,會執行
這個函數
Hello there today's date is 2017-08-29
[root@redhat7 script]#./func1.sh ---但執行腳本時調用這個函數就執
行不了,說明執行腳本時是開了一個當前shell的子進程,而hello這個
函數不在子進程里,所以無法調用
./func1.sh: line 3: hello: command not found
[root@redhat7 script]#export -f hello  ---聲明hello這個函數是環境函
數,就可以將函數傳給子進程,讓子進程也可以使用,當然不聲明也
可以,在當前腳本中再執行一次source /root/funcs,把函數文件載入到當前腳本
的shell中。
[root@redhat7 script]#./func1.sh 
Hello there today's date is 2017-08-29
[root@redhat7 script]#
還可以使用declare -xf 聲明是環境函數,跟export -f一樣。
declare -x 聲明是環境變量=export

10、函數參數

?函數可以接受參數:
傳遞參數給函數:調用函數時,在函數名后面以空白分隔給定參數列表即可;例如“testfun carg1 arg2 ...”
在函數體中當中,可使用$1, $2, ...調用這些參數;還可以使用$@, $*, $#等特殊變量
但不能使用$0,$0表示帶路徑的當前腳本的名字,不能代表函數名,這一點和腳本不同,其他的參數調用和腳本都類似。
示例

[root@redhat7 script]#vim functions 
hello () {
        echo "Hello there today's date is `date +%F`"
}
add () {              ---定義一個函數,讓傳給函數的參數進行加運算
       echo $[$1+$2]
}
[root@redhat7 script]#vim func1.sh
#!/bin/bash
#
source functions
add 1 2   ---調用函數時加上參數
[root@redhat7 script]#./func1.sh ---執行結果
3

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)!

[root@redhat7 script]#vim jiecheng.sh 
#!/bin/bash
#
fact () {
      if [ $1 -eq 0 -o $1 -eq 1 ];then
             echo 1
      else
            echo $[$1*`fact $[$1-1]`]  ---函數自己調用自己
          fi
}
fact $1
[root@redhat7 script]#./jiecheng.sh 4
24

12、fork炸彈

?fork炸彈是一種惡意程序,它的內部是一個不斷在fork進程的無限循環,實質是一個簡單的遞歸程序。由于程序是遞歸的,如果沒有任何限制,這會導致這個簡單的程序迅速耗盡系統里面的所有資源
?函數實現
:(){ :|:& };:
bomb() { bomb | bomb & }; bomb
?腳本實現

cat Bomb.sh
#!/bin/bash
./$0|./$0&   ---腳本調用腳本

13、如何實現打印正確和錯誤時顯示ok和FAILED

[root@redhat7 script]#vim ok.sh
#!/bin/bash
#
. /etc/init.d/functions   ---將這個函數文件讀入到當前腳本中
action "success! " true  ---調用函數文件里的action這個函數,其中true可以用任何返回結果為真的代替
action "failed"   false ---false可以用任何返回結果為假的代替
[root@redhat7 script]#./ok.sh
success!                                                   [  OK  ]
failed                                                     [FAILED]
最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 228,156評論 6 531
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 98,401評論 3 415
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事?!?“怎么了?”我有些...
    開封第一講書人閱讀 176,069評論 0 373
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 62,873評論 1 309
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 71,635評論 6 408
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 55,128評論 1 323
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,203評論 3 441
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,365評論 0 288
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 48,881評論 1 334
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 40,733評論 3 354
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 42,935評論 1 369
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,475評論 5 358
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,172評論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,582評論 0 26
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,821評論 1 282
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 51,595評論 3 390
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 47,908評論 2 372

推薦閱讀更多精彩內容