循環的特殊用法:
1、while循環的特殊用法之遍歷文件的每一行
while read line; do 循環體 done < /PATH/FROM/SOMEFILE依次讀取/PATH/FROM/SOMEFILE文件中的每一行,將每一行賦值給變量line,從而實現對文件的增刪改
練習:掃描/etc/passwd 文件每一行,如發現GECOS 字段為空,則填充用戶名和單位電話為62985600 ,并提示該用戶的GECOS信息修改成功。
#!/bin/bash #description if user no gecos add something to gecos #version 0.1 #author gaomeng #date 20160819 # while read line ; do gecos=`echo $line | cut -d: -f5` if [ -z $gecos ] &> /dev/null ; then username=`echo $line | cut -d: -f1` usermod -c "$username 62985600" $username echo "$username gecos is changed." fi done < /etc/passwd[root@CentOS6 bin]# getent passwd gao gao:x:500:500::/home/gao:/bin/bash //gecos段無信息 [root@CentOS6 bin]# addgecos.sh abrt gecos is changed. ntp gecos is changed. postfix gecos is changed. gdm gecos is changed. tcpdump gecos is changed. hlr gecos is changed. gao gecos is changed. hadoop gecos is changed. test gecos is changed. [root@CentOS6 bin]# getent passwd gao gao:x:500:500:gao 62985600:/home/gao:/bin/bash //gecos段有信息
2、C語言風格的for循環:
雙小括號方法,即((…))格式,代替shell中的in LIST 菜單
單純用(( ))也可重定義變量值,比如 a=5; ((a++))可將$a重定義為6
for 循環的C語言風格:
for ((控制變量的初始化; 退出此for循環的條件; 控制變量的修正表達式)) do 循環體 done控制變量初始化:僅在運行到循環代碼段時執行一次
控制變量的修正表達式:每輪循環結束會先進行控制變量修正運算,而后再做退出for循環的條件判斷,若滿足條件則退出循環,若不滿足則繼續循環
例如:打印99乘法表
#!/bin/bash #description echo 9 * 9 #version 0.1 #author gaomeng #date 20160819 # for (( i=1 ; i<=9 ; i++ )) do for (( j=1 ; j<=i ; j++ )) do echo -en "$j*$i=$[$i*$j]\t" done echo done[root@CentOS6 bin]# bash for99.sh 1*1=1 1*2=2 2*2=4 1*3=3 2*3=6 3*3=9 1*4=4 2*4=8 3*4=12 4*4=16 1*5=5 2*5=10 3*5=15 4*5=20 5*5=25 1*6=6 2*6=12 3*6=18 4*6=24 5*6=30 6*6=36 1*7=7 2*7=14 3*7=21 4*7=28 5*7=35 6*7=42 7*7=49 1*8=8 2*8=16 3*8=24 4*8=32 5*8=40 6*8=48 7*8=56 8*8=64 1*9=9 2*9=18 3*9=27 4*9=36 5*9=45 6*9=54 7*9=63 8*9=72 9*9=81
3、select循環與菜單
select variable in list do 循環體命令 donea.select循環主要用于創建菜單,按數字順序排列的示菜單項將顯示在標準錯誤上,并顯示PS3提示符,等待用戶輸入,用戶也可在腳本中修改PS3提示符,使之更加人性化
b.用戶輸入菜單列表中的某個數字,執行數字后所相應的命令
c.用戶輸入被保存在內置變量REPLY中,可以在語句中打印此變量
d.select是個無限循環,因此要記住用break命令退出循環,或用exit命令終止腳本。也可以按 ctrl+c退出循環。
e.select經常和case聯合使用
f.與for循環類似,可以省略 in list,此時使用位置參量
例如:1.沒有修改PS3提示符,也沒有配合case語句使用
#!/bin/bash #description show select #version 0.1 #authre gaomeng #date 20160819 # select list in gongbaojiding hongshaorou huobaofeichang shaopaigu do echo $list done[root@CentOS6 bin]# select.sh 1) gongbaojiding 2) hongshaorou 3) huobaofeichang 4) shaopaigu #? 1 gongbaojiding #? 2 hongshaorou #? 3 huobaofeichang #? 4 shaopaigu #? 5 #? 6 #? ^C2.修改了PS3,配合使用了case語句:
#!/bin/bash #description show select #version 0.3 #authre gaomeng #date 20160819 # PS3="What do you want:" select list in gongbaojiding hongshaorou huobaofeichang shaopaigu do case $list in gongbaojiding) echo "$list is 20¥" exit;; hongshaorou) echo "$list is 30¥" exit;; huobaofeichang) echo "$list is 25¥" exit;; shaopaigu) echo "$list is 40¥" exit;; *) echo "no the list, please choice other." esac done[root@CentOS6 bin]# select.sh 1) gongbaojiding 2) hongshaorou 3) huobaofeichang 4) shaopaigu What do you want:1 gongbaojiding is 20¥ [root@CentOS6 bin]# select.sh 1) gongbaojiding 2) hongshaorou 3) huobaofeichang 4) shaopaigu What do you want:4 shaopaigu is 40¥ [root@CentOS6 bin]# select.sh 1) gongbaojiding 2) hongshaorou 3) huobaofeichang 4) shaopaigu What do you want:8 no the list, please choice other. What do you want:3 huobaofeichang is 25¥
函數:
函數function是由若干條shell命令組成的語句塊,實現代碼重用和模塊化編程,即有個功能或模塊,我們在代碼中會反復使用,則可以寫成函數,使用是調用函數即可,而不用多次編寫代碼
它與shell程序形式上是相似的,不同的是它不是一個單獨的進程,不能獨立運行,而是shell程序的一部分
函數和shell程序比較相似,區別在于:
Shell程序在子Shell中運行
而Shell函數在當前Shell中運行。因此在當前Shell中,函數可以對shell中變量進行修改
函數的定義:
函數在使用前必須定義,因此應將函數定義放在腳本開始部分,直至shell調用它后才能使用
定義:
函數由兩部分組成:函數名和函數體。
語法一:
function f_name {
… 函數體…
}
語法二:
function f_name () {
… 函數體…
}
語法三:
f_name() {
… 函數體…
}
a.可在交互式環境下定義函數
b.可將函數放在腳本文件中作為它的一部分
c.可放在只包含函數的單獨文件中,在腳本中用source 和. 調用函數
d.可以將經常使用的函數存入函數文件,然后將函數文件載入shell
e.文件名可任意選取,但最好與相關任務有某種聯系。例如:functions.main
f.一旦函數文件載入shell,就可以在命令行或腳本中調用函數??梢允褂胹et命令查看所有定義的函數,其輸出列表包括已經載入shell的所有函數。
g.若要改動函數,首先用unset命令從shell中刪除函數。改動完畢后,再重新載入此文件。
載入函數:
shell腳本中調用一個已創建好函數文件:
. filename 或 source filename
注意:此處<點> <空格> <文件名>
這里的文件名要使用路徑,絕對路徑或者相對路徑都可以
調用函數:
函數只有被調用才會執行;
調用函數僅使用其函數名即可
函數名出現的地方,會被自動替換為函數代碼
函數的生命周期:被調用時創建,返回時終止
刪除函數:
使用unset命令完成此功能.
unset function_name
函數的返回值:
函數的執行結果返回值:
(1) 使用echo或printf命令進行輸出
(2) 函數體中調用命令的輸出結果
函數的退出狀態碼:
(1) 默認取決于函數中執行的最后一條命令的退出狀態碼
(2) 自定義退出狀態碼,其格式為:
return 從函數中返回,用最后狀態命令決定返回值
return 0 無錯誤返回。
return 1-255 有錯誤
函數參數:
函數可以接受參數:
傳遞參數給函數:調用函數時,在函數名后面以空白分隔給定參數列表即可;例如“testfunc arg1 arg2 …”
在函數體中當中,可使用$1, $2, … 調用這些參數;還可以使用$@, $*, $# 等特殊變量
注意:請區分函數中的$1和腳本的$1不同之處
例如:如下腳本
#!/bin/bash #description test function $1 $2 #version 0.1 #author gaomeng #date 20160819 # prin() { echo "prin function \$1 is $1." echo "prin function \$2 is $2." } echo "\$1 is $1." echo "\$2 is $2." prin $2 $1[root@CentOS6 bin]# functiontest.sh 3 9 $1 is 3. $2 is 9. prin function $1 is 9. prin function $2 is 3.
函數變量:
變量作用域:
a.環境變量:當前shell和子shell有效
b.本地變量:只在當前shell 進程有效,為執行腳本會啟動專用子shell進程;因此,本地變量的作用范圍是當前shell腳本程序文件,包括腳本中的函數。
c.局部變量:函數的生命周期;函數結束時變量被自動銷毀
注意:如果函數中有局部變量,如果其名稱同本地變量,使用局部變量。
在函數中定義局部變量的方法
local NAME=VALUE
#!/bin/bash #description #version 0.1 #author gaomeng #date 20160819 # test1() { echo "test1 name=$name" //沒有定義變量 } test2() { local name=haha //定義了局部變量 echo "test2 name=$name" } test3() { name=haha //直接定義了一個變量,會影響腳本中的變量值? echo "test3 name=$name" } name=gaomeng echo "name=$name" test1 echo "name=$name" test2 echo "name=$name" test3 echo "name=$name"[root@CentOS6 bin]# bash functiontest1.sh name=gaomeng test1 name=gaomeng //函數中沒有定義變量,則自動使用腳本中的同名變量 name=gaomeng test2 name=haha name=gaomeng //在函數中定義的局部變量沒有影響腳本中的變量 test3 name=haha name=haha //在函數中定義的變量影響了腳本中的變量
函數遞歸:
函數直接或間接調用自身
注意遞歸層數
遞歸實例:
階乘是基斯頓·于 卡曼于 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 5
練習:1、寫一個函數實現兩個數字做為參數,返回最大值
#!/bin/bash #description input two number, and retuen max number. #version 0.1 #author gaomeng #date 20160818 # max(){ if [ $1 -gt $2 ]; then echo "max number is: $1" else echo "max number is: $2" fi } read -p "Input first number: " num1 until echo $num1 | grep -qE "^[0-9]+$";do read -p "your number error, Input first number: " num1 done read -p "Input second number: " num2 until echo $num2 | grep -qE "^[0-9]+$";do read -p "your number error, Input second number: " num2 done max $num1 $num2
[root@CentOS6 bin]# function3.sh Input first number: sdf your number error, Input first number: 123 Input second number: -124 your number error, Input second number: sdkf your number error, Input second number: 100 max number is: 1232、寫一個函數實現數字的加減乘除運算,例如輸入 1 + 2 ,,將得出正確結果
#!/bin/bash #desription four arithmetic operation #version 0.1 #author gaomeng #date 20160818 # operation() { if [ $2 == "+" ]; then echo "$1+$3=$[$1+$3]" elif [ $2 == "-" ]; then echo "$1-$3=$[$1-$3]" elif [ $2 == "x" ]; then echo "${1}x${3}=$[$1*$3]" elif [ $2 == "/" ]; then echo "$1/$3=$[$1/$3]" else echo "this is error symbol." fi } read -p "Input first number: " num1 until echo $num1 | grep -qE "^\-?[0-9]+$";do read -p "your number error, Input first number: " num1 done i=0 until [ $i -eq 1 ];do read -p "Input operation symbol( please x instead of * ): " num2 [ $num2 == "+" -o $num2 == "-" -o $num2 == "x" -o $num2 == "/" ] &> /dev/null &&i=1 done read -p "Input second number: " num3 until echo $num3 | grep -qE "^\-?[0-9]+$";do read -p "your number error, Input second number: " num3 done operation $num1 $num2 $num3[root@CentOS6 bin]# function4.sh Input first number: sdf your number error, Input first number: 5 Input operation symbol( please x instead of * ): * Input operation symbol( please x instead of * ): x Input second number: -4 5x-4=-203、斐波那契數列又稱黃金分割數列,因數學家列昂納多·斐波那契以兔子繁殖為例子而引入,故又稱為“兔子數列”,指的是這樣一個數列:0 、1 、1 、2 、3 、5 、8 、13 、21 、34 、…… ,斐波納契數列以如下被以遞歸的方法定義:F (0 )=0 ,F (1 )=1 ,F (n )=F(n-1)+F(n-2) (n≥2) )
寫一個函數,求n 階斐波那契數列
0 1 2 3 4 5 6 7 8 9
0、1 、1 、2 、3 、5 、8 、13 、21 、34
#!/bin/bash #description series of rabbit #version 0.3 #author gaomeng #date 20160818 # series() { if [ $1 -eq 0 ]; then sum=0 elif [ $1 -eq 1 ];then sum=1 else let sum=`series $[$1-1]`+`series $[$1-2]` fi echo "$sum" } read -p "Please input month number: " num until echo $num | grep -qE "^[0-9]+$";do read -p "your number error, Input month number: " num done series $num[root@CentOS6 bin]# function5.sh Please input month number: -123 your number error, Input month number: sdf your number error, Input month number: 8 21 [root@CentOS6 bin]# function5.sh Please input month number: 1.02323 your number error, Input month number: 10 554、漢諾塔(又稱河內塔)問題是源于印度一個古老傳說。大梵天創造世界的時候做了三根金剛石柱子,在一根柱子上從下往上按照大小順序摞著64片黃金圓盤。大梵天命令婆羅門把圓盤從下面開始按大小順序重新擺放在另一根柱子上。并且規定,在小圓盤上不能放大圓盤,在三根柱子之間一次只能移動一個圓盤。
利用函數,實現N片盤的漢諾塔的移動步驟
#!/bin/bash #description hanoi game #version 0.2 #author gaomeng #date 20160818 # i=1 move() { echo -e "$i)\t$1 plate from $2 to $3." let i++ } 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 } read -p "Please input move plate numbers: " num until echo $num | grep -qE "^[0-9]+$";do read -p "your number error, Input move plate number: " num done hanoi $num A B C[root@CentOS6 bin]# function6.sh Please input move plate numbers: 3 1)1 plate from A to C. 2)2 plate from A to B. 3)1 plate from C to B. 4)3 plate from A to C. 5)1 plate from B to A. 6)2 plate from B to C. 7)1 plate from A to C. [root@CentOS6 bin]# function6.sh Please input move plate numbers: 4 1)1 plate from A to B. 2)2 plate from A to C. 3)1 plate from B to C. 4)3 plate from A to B. 5)1 plate from C to A. 6)2 plate from C to B. 7)1 plate from A to B. 8)4 plate from A to C. 9)1 plate from B to C. 10)2 plate from B to A. 11)1 plate from C to A. 12)3 plate from B to C. 13)1 plate from A to B. 14)2 plate from A to C. 15)1 plate from B to C.
原創文章,作者:megedugao,如若轉載,請注明出處:http://www.www58058.com/37631