目录
1. 求两数之和
整数之和
浮点数之和
2. 计算1-100的和
for...in
C风格for循环
while...do
until...do
while和until的区别
关系运算符
break与continue的区别
3. shell函数基础知识
函数定义
函数名
函数体
参数
返回值
return返回值的含义
return与echo返回值的区别
4. 自定义库函数
定义库函数
调用库函数
执行结果
5. 递归函数
递归法实现阶乘函数
改用循环实现
shell程序的数字类型只有整数类型一种,并不支持浮点数。如:
hann@HannYang:~$ cat sum.sh
#!/bin/bash
# 读取第一个数
echo "请输入第一个数:"
read a
# 读取第二个数
echo "请输入第二个数:"
read b
# 计算两个数的和
sum=$(( a + b ))
# 输出结果
echo "这两个数的和为:$sum"
hann@HannYang:~$ bash sum.sh
请输入第一个数:
5
请输入第二个数:
3
这两个数的和为:8
hann@HannYang:~$
在shell编程中,浮点数只能被用作字符串来操作,脚本语法本身不提供浮点数的操作方法,但可以调用bc, awk等外部命令来计算并返回结果。如:
hann@HannYang:~$ cat sum2.sh
#!/bin/bash
num1=3.14
num2=2.72
# 计算和
sum=$(echo "$num1 + $num2" | bc)
echo "$num1 + $num2 = $sum"
sum=$(echo $num1 $num2 | awk '{print $1+$2}')
echo "$num1 + $num2 = $sum"
hann@HannYang:~$ bash sum2.sh
3.14 + 2.72 = 5.86
3.14 + 2.72 = 5.86
用1~100累和的例子,示例循环结构的各种语句的写法:
hann@HannYang:~$ sum=0;for i in {1..100};do let sum+=i;done;echo $sum
hann@HannYang:~$ sum=0;for ((i=1; i<=100; i++));do let sum+=i;done;echo $sum
sum=0 # 初始化变量sum为0
i=1 # 初始化计数器i为1
while [ $i -le 100 ]; do # 当计数器i小于等于100时执行循环体
let sum+=i # 将当前整数累加到sum中
i=$((i+1)) # 计数器自增1
done # 结束循环
echo $sum # 打印出变量sum的值
sum=0 # 初始化变量sum为0
i=1 # 初始化计数器i为1
until [ $i -gt 100 ]; do # 当计数器i大于100时执行循环体
let sum+=i # 将当前整数累加到sum中
i=$((i+1)) # 计数器自增1
done # 结束循环
echo $sum # 打印出变量sum的值
while循环是当条件测试为真时执行,为假时退出循环
until循环是当条件测试为假时执行,为真时退出循环
while A; do 等价于 until not A; do
until A; do 等价于 while not A; do
while [ ! $i -gt 100 ]; do <==> until [ $i -gt 100 ]; do
until [ ! $i -le 100 ]; do <==> while [ $i -le 100 ]; do
-eq equal 即 ==,检测两个数是否相等,相等返回 true。
-ne not equal 即 !=,检测两个数是否不相等,不相等返回 true。
-gt great than 即 >,检测左边的数是否大于右边的,如果是,则返回 true。
-lt less than 即 <,检测左边的数是否小于右边的,如果是,则返回 true。
-ge great equal 即>=,检测左边的数是否大于等于右边的,如果是,则返回 true。
-le less equal,即<=,检测左边的数是否小于等于右边的,如果是,则返回 true。
break语句用于退出本层循环,当执行到break会立即跳出当前循环,执行后续代码。
在多层嵌套循环中,break只会跳出最近的一层循环。
continue语句用于结束本次循环,跳过本次循环中剩余的代码,直接进入下一次循环。
在多层嵌套循环中,continue只会跳过最近的一层循环。
两种语句的基本用法与其它语言的基本一样,不另举例说明。
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"
最后结果是从$?获取的,其实$?与其它语言中函数返回值是有区别 ,$? 本质上是返回上一条命令的退出状态,并且只是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
@ =
* =
$?只能函数执行后调用,$#,$@,$*只能在函数内部调用,$$则在函数内外都能调用。
为了显示两者的不通,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!
"$@"的应用: 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"
完