目录
shell函数基础知识
函数定义
函数名
函数体
参数
返回值
return返回值的含义
return与echo返回值的区别
可变参数函数
自定义库函数
定义库函数
调用库函数
执行结果
递归函数
阶乘函数
斐波那契函数
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 $@表示遍历所有参数组成的“可迭代数组”。
示例:
#!/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
完