shell脚本编程-函数
函数是Shell脚本中自定义的一系列执行命令,一般来说函数应该设置返回值.
语法:
#shell中的函数定义 #其中function为关键字,FUNCTION_NAME为函数名 funciton FUNCTON_NAME(){ command1 #函数体中可以有多个语句,不允许有空语句 command2 ... } #省略关键字function,效果一样 FUNCTION_NAME(){ command1 command2 ... }
eg:
1 [rhat@localhost shell]$ vim sayHello.sh 2 #!/bin/bash 3 function sayHello(){ 4 echo "Hello" 5 } 6 echo "Call function sayHello" 7 sayHello 8 [rhat@localhost shell]$ sh ./sayHello.sh 9 Call function sayHello 10 Hello
or
1 [rhat@localhost shell]$ vim countLine.sh 2 #!/bin/bash 3 FILE=/etc/passwd 4 function countLine(){ 5 local i=0 6 while read line 7 do 8 let ++i 9 done < $FILE 10 echo "$FILE have $i lines" 11 } 12 echo "Call function countLine" 13 countLine 14 #执行结果 15 [rhat@localhost shell]$ sh ./countLine.sh 16 Call function countLine 17 /etc/passwd have 31 lines
函数的返回值又叫函数的返回状态,实际上是一种通信方式.获取上一个命令返回值得方式是使用$?
eg:
1 [rhat@localhost shell]$ vim checkFileExist.sh 2 #!/bin/bash 3 FILE=/etc/notExistFile 4 function checkFileExist(){ 5 if [ -f $FILE ];then 6 return 0 7 else 8 return 1 9 fi 10 } 11 echo "Call function checkFileExist" 12 checkFileExist #调用函数 13 if [ $? -eq 0 ];then 14 echo "$FILE exist" 15 else 16 echo "$FILE not exist" 17 fi 18 #执行结果 19 [rhat@localhost shell]$ sh ./checkFileExist.sh 20 Call function checkFileExist 21 /etc/notExistFile not exist
or
1 [rhat@localhost shell]$ vim checkNum.sh 2 #!/bin/bash 3 function checkNum(){ 4 echo -n "Please input a number:" 5 read NUM 6 if [ $NUM -ge 0 -a $NUM -lt 10 ];then 7 return 0 8 fi 9 if [ $NUM -ge 10 -a $NUM -lt 20 ];then 10 return 1 11 fi 12 if [ $NUM -ge 20 -a $NUM -lt 30 ];then 13 return 2 14 fi 15 return 3 16 } 17 echo "Call function checkNum" 18 checkNum 19 RTV=$? 20 if [ $RTV -eq 0 ];then 21 echo "The number is between[0,10]" 22 elif [ $RTV -eq 1 ];then 23 echo "The number is between[10,20]" 24 elif [ $RTV -eq 2 ];then 25 echo "The number is between[20,30]" 26 else 27 echo "Unknown input" 28 fi 29 #执行结果 30 [rhat@localhost shell]$ sh ./checkNum.sh 31 Call function checkNum 32 Please input a number:30 33 Unknown input
向函数传递参数是使用位置参数来实现的.
1 [rhat@localhost shell]$ vim checkFileExist_v2.sh 2 #!/bin/bash 3 function checkFileExist(){ 4 if [ -f $1 ];then 5 return 0 6 else 7 return 1 8 fi 9 } 10 echo "Call function checkFileExist" 11 checkFileExist $1 12 if [ $? -eq 0 ];then 13 echo "$FILE exist" 14 else 15 echo "$FILE not exist" 16 fi 17 #执行结果. 18 [rhat@localhost shell]$ sh ./checkFileExist_v2.sh haha.txt 19 Call function checkFileExist 20 not exist
or
1 [rhat@localhost shell]$ vim power.sh 2 #!/bin/bash 3 function power(){ 4 RESULT=1 5 LOOP=0 6 while [[ "$LOOP" -lt $2 ]] 7 do 8 let "RESULT=RESULT*$1" 9 let "LOOP+=1" 10 done 11 echo $RESULT 12 } 13 echo "Call function power with parameters" 14 power $1 $2 15 #执行结果 16 [rhat@localhost shell]$ sh ./power.sh 3 3 17 Call function power with parameters 18 27
除了在脚本运行时给脚本传入位置参数外,还可以使用内置命令set命令给脚本指定位置参数的值.(又叫重置)
1 [rhat@localhost shell]$ vim set01.sh 2 #!/bin/bash 3 set 1 2 3 4 5 6 4 COUNT=1 5 for i in $@ 6 do 7 echo "Here \$$COUNT is $i" 8 let "count++" 9 done 10 #执行结果 11 [rhat@localhost shell]$ sh ./set01.sh a b c d e f 12 Here $1 is 1 13 Here $1 is 2 14 Here $1 is 3 15 Here $1 is 4 16 Here $1 is 5 17 Here $1 is 6
在shell中使用shift命令移动位置参数.shift命令可以让位置参数左移一位.
1 [rhat@localhost shell]$ vim shift03.sh 2 #!/bin/bash 3 until [ $# -eq 0 ] 4 do 5 echo "Now \$i is :$1,total parameter is:$#" 6 shift #加数字 2 表示 左移2个参数,eg: shift 2 7 done 8 #执行结果 9 [rhat@localhost shell]$ sh ./shift03.sh 1 2 3 a v c 10 Now $i is :1,total parameter is:6 11 Now $i is :2,total parameter is:5 12 Now $i is :3,total parameter is:4 13 Now $i is :a,total parameter is:3 14 Now $i is :v,total parameter is:2 15 Now $i is :c,total parameter is:1
对某些很常用的功能,必须考虑将其独立出来,集中存放在一些独立的文件中,这些文件就称为”文件库“,在实践中建议库函数使用下划线开头.
eg:lib01.sh 函数库.
1 [rhat@localhost shell]$ vim lib01.sh 2 _checkFileExist(){ 3 if [ -f $1 ];then 4 echo "File:$1 exist" 5 else 6 echo "File:$1 not exist" 7 }
加载函数库的两种方式:
1 #使用”点“.命令。 2 [rhat@localhost shell]$ . ./lib01.sh # / 前面的.表示当前目录,,别搞混。 3 #使用source命令。 4 [rhat@localhost shell]$ source ./lib01.sh
脚本中调用函数库.
1 [rhat@localhost shell]$ vim callLib01.sh 2 #!/bin/bash 3 source ./lib01.sh #引用函数库到当前shell. 4 _checkFileExist /etc/notExistFile 5 _checkFileExist /etc/passwd 6 #执行结果 7 [rhat@localhost shell]$ sh ./callLib01.sh 8 File:/etc/notExistFile not exist 9 File:/etc/passwd exist
很多Linux发行版中都有/etc/init.d目录,这是系统中放置所有开机启动脚本的目录,这些开机脚本在脚本开始运行时都会加载/etc/init.d/functions 或/etc/rc.d/init.d/functionshanshuku.(两个库内容实际上完全一样. 如下:
1 # Source functions library 2 . /etc/init.d/functions 3 或者 4 # Source functions library 5 . /etc/rc.d/init.d/functions
在脚本中使用functions函数库.
1 [rhat@localhost shell]$ vim callFunctions01.sh 2 #!/bin/bash 3 source /etc/init.d/functions 4 confirm ITEM #confirm 实际上是functions库中的一个函数功能. 5 if [[ $? -eq 0 ]];then 6 echo "ITEM confirmed" 7 else 8 echo "ITEM not confirmed" 9 fi 10 #执行结果. 11 [rhat@localhost shell]$ sh ./callFunctions01.sh 12 Start service ITEM (Y)es/(N)o/(C)ontinue? [Y] y 13 ITEM confirmed
functions库中常用的函数:
checkpid() | 检查某个PID是否存在 |
daemon() | 以deamon方式启动某个服务 |
killproc() | 停止某个进程 |
pidfileofproc() | 检查某个进程的PID文件 |
pidofproc() | 检查某个进程的PID |
status() | 判断某个服务的状态 |
echo_success() | 打印OK |
echo_failure() | 打印FAILED |
echo_passed() | 打印PASSED |
echo_warning() | 打印WARNING |
success() | 打印OK并记录日志 |
failure() | 打印FAILED并记录日志 |
passed() | 打印PASSED并记录日志 |
warning() | 打印WARNING并记录日志 |
action() | 执行给定的命令,并根据执行结果打印信息 |
strstr() | 检查$1字符串中是否含有$2字符串 |
confirm() | 提示是否启动某个服务. |
在函数中继续调用函数自身,注意调用条件,否则会毫无止境的调用,语法:
function recursion(){ recursion confitionThatEndTheRecursion #停止递归的条件. }
例如阶乘函数:n!=1x2x3x4x...xn.
1 [rhat@localhost shell]$ cat factorial01.sh 2 #!/bin/bash 3 function factorial01(){ 4 local NUMBER=$1 5 if [ $NUMBER -le 0 ];then 6 RES=1 7 else 8 factorial01 $((NUMBER-1)) 9 TEMP=$RES 10 NUMBER=$NUMBER 11 RES=$((NUMBER*TEMP)) 12 fi 13 } 14 factorial01 $1 15 echo $RES 16 #执行结果 17 [rhat@localhost shell]$ sh -x ./factorial01.sh 4 #-x为观察执行过程的细节. 18 + factorial01 4 19 + local NUMBER=4 20 + '[' 4 -le 0 ']' 21 + factorial01 3 22 + local NUMBER=3 23 + '[' 3 -le 0 ']' 24 + factorial01 2 25 + local NUMBER=2 26 + '[' 2 -le 0 ']' 27 + factorial01 1 28 + local NUMBER=1 29 + '[' 1 -le 0 ']' 30 + factorial01 0 31 + local NUMBER=0 32 + '[' 0 -le 0 ']' 33 + RES=1 34 + TEMP=1 35 + NUMBER=1 36 + RES=1 37 + TEMP=1 38 + NUMBER=2 39 + RES=2 40 + TEMP=2 41 + NUMBER=3 42 + RES=6 43 + TEMP=6 44 + NUMBER=4 45 + RES=24 46 + echo 24 47 24
linux shell 汉诺塔实现:我没理解得了.((~﹃~)~zZ)
1 [rhat@localhost shell]$ vim hanoi01.sh 2 #!/bin/bash 3 function hanoi01(){ 4 local num=$1 5 if [ "$num" -eq "1" ]; then 6 echo "Move:$2---->$4" 7 else 8 hanoi01 $((num-1)) $2 $4 $3 9 echo "Move:$2---->$4" 10 hanoi01 $((num-1)) $3 $2 $4 11 fi 12 } 13 hanoi01 4 A B C 14 #执行结果 15 [rhat@localhost shell]$ sh ./hanoi01.sh 16 Move:A---->B 17 Move:A---->C 18 Move:B---->C 19 Move:A---->B 20 Move:C---->A 21 Move:C---->B 22 Move:A---->B 23 Move:A---->C 24 Move:B---->C 25 Move:B---->A 26 Move:C---->A 27 Move:B---->C 28 Move:A---->B 29 Move:A---->C 30 Move:B---->C
嵌套函数天生的结构就注定了其晦涩的可读性,在不少大公司内部的开发规范中也明确规定了不允许使用递归,所以在实际工作中药尽量避免使用递归.