shell函数基础知识
函数定义
函数名
Shell函数用关键字 function 声明,跟在后面的 name 即函数名。声明后就用"函数名 [参数]"来调用函数。function 非必须,也能用函数名加一对括号 name() { ... } 来声明定义函数。
函数体
函数名后的 { Commands; } 即函数体,是实现函数功能的主体。
参数
Shell函数可以通过参数接收输入的值。在函数定义时,可以在括号中指定参数列表。参数可以在函数体中使用,也可以通过特殊变量#获取函数的参数个数,通过特殊变量#获取函数的参数个数,通过特殊变量#获取函数的参数个数,通过特殊变量@获取所有的参数。
返回值
Shell函数可以有一个返回值,可以使用return语句返回一个值。返回值的范围是0到255之间,0表示成功,非零值表示错误。如果函数中没有return语句,或者使用exit命令退出函数,则函数的返回值为退出命令的返回值。
如一个计算2数之和的函数:
#!/bin/bash function add() { local a=$1 local b=$2 local res=$((a + b)) return $res } add 3 5 result=$? echo "The result is: $result"
return返回值的含义
最后结果是从获取的,其实?获取的,其实?获取的,其实?与其它语言中函数返回值是有区别 ,$? 本质上是返回上一条命令的退出状态,并且只是0~255间的整数,也就是最多返回256种状态。
除了$?还有另外4个特殊的变量,它们分别表示以下含义:
$$
:表示当前Shell进程的进程ID(PID)。$#
:表示传递给脚本或函数的参数个数。$@
:表示以空格分隔的所有参数,将所有参数视为单个字符串。$*
:表示所有参数作为单独的字符串展开,每个参数之间用一个空格分隔。
例程:
hann@HannYang:~$ more sum3.sh #!/bin/bash function special_vars() { echo "Current PID \$: $$" echo "Number of arguments #: $#" echo "All arguments (as a single string) @: $@" echo "All arguments separated by spaces *: $*" echo return $(($1+$2+$3)) } special_vars 1 2 3 4 5 echo "? = "$? echo "\$ = "$$ echo "# = "$# echo "@ = "$@ echo "* = "$* hann@HannYang:~$ bash sum3.sh Current PID $: 1679 Number of arguments #: 5 All arguments (as a single string) @: 1 2 3 4 5 All arguments separated by spaces *: 1 2 3 4 5 ? = 6 $ = 1679 # = 0 @ = * =
?只能函数执行后调用,?只能函数执行后调用,?只能函数执行后调用,#,@,@,*只能在函数内部调用,$$则在函数内外都能调用。
return与echo返回值的区别
为了显示两者的不通,echo后加了“sum=”,而return只能返回整数0~255。
例程:
#!/bin/bash function add() { local a=$1 local b=$2 local res=$((a + b)) echo sum=$res return $res } Result=$(add 100 155) echo "The result is: $?" echo "The result is: $Result" Result=$(add 100 156) echo "The result is: $?" echo "The result is: $Result" Result=$(add 155 358) echo "The result is: $?" echo "The result is: $Result" echo "The result is: $(( (155+358)%256 ))"
输出:
The result is: 255
The result is: sum=255
The result is: 0
The result is: sum=256
The result is: 1
The result is: sum=513
The result is: 1
注意:
return 返回表达式的值,如溢出范围可以认为是 表达式与256相余的结果。
所以shell函多用echo来返回一个字串结果$res再进行调用,而return一般不会作函数值返回语句,它的真实用途是来返回程序运行状态的,比如:
例1:
hann@HannYang:~$ cat test.sh #!/bin/bash function filecount { # 检查目录是否存在 if [ -d "$1" ]; then # 目录存在,计算文件数 echo $(ls -l "$1" | grep "^-" | wc -l) return 1 else # 目录不存在,返回0 return 0 fi } dir="$1" count=$(filecount $dir) if [ $? = 1 ] then echo "Dir $dir exists,files:$count" else echo "Dir $dir does'nt exist." fi dir="$2" count=$(filecount $dir) if [ $? = 0 ] then echo "Dir $dir does'nt exist." else echo "Dir $dir exists,files:$count" fi hann@HannYang:~$ bash test.sh rust golang Dir rust exists,files:4 Dir golang does'nt exist.
例2:
hann@HannYang:~$ cat chkpid.sh checkpid() { #定义本地变量i local i #使用for循环遍历传递给此函数的所有参数 for i in $* do #如果目录/proc/$i存在,则执行此函数返回0 #在一般的Linux系统中,如果进程正在运行,则在/proc目录下会存在一个以进程号命名的子目录 [ -d "/proc/$i" ] && return 0 done #返回1 return 1 } #调用函数checkpid checkpid $1 $2 $3 if [ $? = 0 ] then echo "The one of them is running." else echo "These PIDS are not running!" fi hann@HannYang:~$ bash chkpid.sh 866 The one of them is running. hann@HannYang:~$ bash chkpid.sh 866 867 1882 The one of them is running. hann@HannYang:~$ bash chkpid.sh 1882 These PIDS are not running! hann@HannYang:~$ bash chkpid.sh 868 1882 These PIDS are not running!
例3:
hann@HannYang:~$ cat prime.sh #!/bin/bash is_prime() { local num=$1 if [ $num -lt 2 ]; then return 1 fi for ((i=2; i*i<=num; i++)); do if [ $((num % i)) -eq 0 ]; then return 1 fi done return 0 } for ((i=1;i<12;i++)); do if `is_prime $i`; then echo "$i 是质数" else echo "$i 不是质数" fi done hann@HannYang:~$ bash prime.sh
输出结果:
1 不是质数
2 是质数
3 是质数
4 不是质数
5 是质数
6 不是质数
7 是质数
8 不是质数
9 不是质数
10 不是质数
11 是质数
可变参数函数
"的应用:@"的应用:in@"的应用: in @表示遍历所有参数组成的“可迭代数组”。
示例:
#!/bin/bash # 定义可变参数的函数 function sum4() { local sum=0 for arg in "$@" do sum=$((sum + arg)) done echo "The sum is: $sum" } # 调用函数并传递参数 sum4 10 20 30 50 sum4 1 2 3 4 5 6
输出:
The sum is: 110
The sum is: 21
自定义库函数
定义库函数
例:写一个函数库,如命名为 math_fun.sh
function add { echo "`expr $1 + $2`" } function sub { echo "`expr $1 - $2`" } function mul { echo "`expr $1 \* $2`" } function div { if [ $2 = 0 ]; then return 0 else echo "`expr $1 / $2`" return 1 fi }
调用库函数
在调用库文件的函数时,使用点符号“ . ” + 库函数文件名(指明文件的绝对路径、相对路径都行)进行调用。如 test_fun.sh :
#!/bin/bash . math_fun.sh add 10 20 sub 90 100 mul 5 6 div 100 25 div 0 100 div 100 0 if [ $? = 0 ];then echo "Error: divide by zero." fi
执行结果
hann@HannYang:~$ bash test_fun.sh
30
-10
30
4
0
Error: divide by zero.
递归函数
递归函数是一种在程序中调用自身的函数。在 Shell 编程中,也能使用递归函数来解决一些问题,例如计算阶乘、斐波那契数列等。
递归函数的实现需要满足以下两个条件:
- 函数必须有一个终止条件,否则会无限循环下去。
- 函数必须能够将问题分解成更小的问题,并且能够通过调用自身来解决这些小问题。
阶乘函数
#!/bin/bash factorial() { if [ $1 -le 1 ] then echo 1 else echo $(( $1 * $(factorial $(( $1 - 1 ))) )) fi } read -p "请输入一个整数:" num result=$(factorial $num) echo "$num 的阶乘为 $result"
改用循环实现:
#!/bin/bash factorial() { local result=1 for ((i=1; i<=$1; i++)) do result=$((result * i)) done echo $result } read -p "请输入一个整数:" num result=$(factorial $num) echo "$num 的阶乘为 $result"
斐波那契函数
#!/bin/bash fibonacci() { if [ $1 -eq 1 ] || [ $1 -eq 2 ]; then echo 1 else echo $(( $(fibonacci $(( $1 - 1 ))) + $(fibonacci $(( $1 - 2 ))) )) fi } for (( i=1; i<=10; i++)); do echo `fibonacci $i`" " done
输出:
1 1 2 3 5 8 13 21 34 55
改用循环实现:
#!/bin/bash fibonacci() { if [ $1 -eq 1 ] || [ $1 -eq 2 ]; then echo 1 else a=1 b=1 for ((i=3;i<=$1;i++)); do c=$((a+b)) a=$b b=$c done echo $c fi } for ((i=1;i<=10;i++)); do echo -n `fibonacci $i`" " done
完