欢迎您的光临,本博所发布之文章皆为作者亲测通过,如有错误,欢迎通过各种方式指正。由于本站位于香港虚拟主机,故速度比较慢。

教程  Shell&Shell脚本基础教程——函数和流程控制

Shell 本站 235 0评论

一、函数


和其他语言一样,在Shell语言中也有着函数。尽管在Shell中函数并非是必须的编程元素,但是通过使用函数,可以对程序进行更加好的组织。将一些相对独立的代码变成函数,可以提高程序的可读性和重用性。避免重复编写大量相同的代码。


1.函数的定义


在Shell中可以通过下面的两种语法来定义函数,分别如下:

shell中函数的定义格式如下:

[ function ] funname [()]

{

    action;


    [return int;]


}

说明:

1、可以带function fun() 定义,也可以直接fun() 定义,不带任何参数。

2、参数返回,可以显示加:return 返回,如果不加,将以最后一条命令运行结果,作为返回值。 return后跟数值n(0-255),还可以通过echo 直接返回。

3、像删除变量一样,删除函数也可以使用 unset 命令,不过要加上 .f 选项,如下所示:

unset .f function_name


函数声明:

1.”function”不可以省略(bash)

function find { 


}


2.不得添加参数

find() { 


}

两种声明方式效果等价。 


注意:

· 函数名和”{“之间必须有空格,shell对空格变态的敏感

· 不得声明形式参数

· 必须在调用前声明

· 无法重载

· 后来的声明会覆盖之前的声明 


函数的命名约定:

· 为了区别变量,建议所有函数名都有小写字母和下划线组成,并以字母开头。

· 不要使用命令作为函数名称。

· 不要在函数名中使用特殊字符。

· 函数名应该尽量体现其功能。


2.函数的调用


当某个函数定义好了以后,用户就可以通过函数名来调用该函数了。在Shell中,函数调用的基本语法如下,

function_name

function_name parm1 parm2 (parm1,parm2...是参数)

注意:

1)调用函数只需要给出函数名,不需要加括号。

2)函数返回值,可以显式增加return语句;如果不加,会将最后一条命令运行结果作为返回值。

3)Shell 函数返回值只能是整数,一般用来表示函数执行成功与否,0表示成功,其他值表示失败。


下面定义了一个 sayhell()的方法,并调用

#! /bin/bash
function sayhello()
{
  echo "Hello,World"
}
sayhello

代码调用结果

[root@VM_156_149_centos shell]# sh hello.sh 

Hello,World


3.函数的返回值


首先,用户利用return来返回某个数值,这个与绝大部分的程序设计语言是相同的。但是 在Shell中,return语句只能返回某个0-255之间的整数值。在Shell中还有一种更优雅的方法帮助用户来获得函数执行后的某个结果,那就是使用echo。在函数中,用户需要将要返回的数据写入到标准输出(stout),通常这个操作是使用echo语句来完成的,然后在调用程序中将函数的执行结果赋值给一个变量。这种做法实际上就是一个命令替换的一个变种。


1 ) 函数使用return返回值

#! /bin/bash
function sum()
{
  returnValue=$(( $1 + $2 ))
  return $returnValue
}
sum 22 4  #调用函数
echo $?

输出:

26


函数返回值在调用该函数后通过 $? 来获得。


函数返回值大于0-255,出错的情况

在上面的执行结果可以看到,所传递的两个数的和被成功的返回。但是通过return只能返回整数值,并且是0-255的范围,如果超出这个范围就会错误的结果。例如将上面的代码换成下面的参数

sum 253 4

则执行结果如下

[root@VM_156_149_centos shell]# sh sum.sh 

1

可以发现,正确的结果应该是257,但是函数的返回值是1.


2 ) 函数使用echo返回值

#! /bin/bash
function length()
{
  str=$1
  result=0
  if [ "$str" != "" ] ; then
      result=${#str}
  fi
  echo "$result"
}
len=$(length "abc123")
echo "The string's length is $len "

函数的调用

[root@VM_156_149_centos shell]# sh length.sh  

The string's length is 6 


4.函数参数


在Shell中,调用函数时可以向其传递参数。在函数体内部,通过 $n 的形式来获取参数的值,例如,$1表示第一个参数,$2表示第二个参数...

例如:

#!/bin/bash
funWithParam(){
    echo "第一个参数为 $1 !"
    echo "第二个参数为 $2 !"
    echo "第十个参数为 $10 !"
    echo "第十个参数为 ${10} !"
    echo "第十一个参数为 ${11} !"
    echo "参数总数有 $# 个!"
    echo "作为一个字符串输出所有参数 $* !"
}
funWithParam 1 2 3 4 5 6 7 8 9 34 73

输出结果:

第一个参数为 1 !

第二个参数为 2 !

第十个参数为 10 !

第十个参数为 34 !

第十一个参数为 73 !

参数总数有 11 个!

作为一个字符串输出所有参数 1 2 3 4 5 6 7 8 9 34 73 !

注意,$10 不能获取第十个参数,获取第十个参数需要${10}。当n>=10时,需要使用${n}来获取参数。


另外,还有几个特殊字符用来处理参数:

参数处理 说明
$# 传递到脚本的参数个数
$* 以一个单字符串显示所有向脚本传递的参数
$$ 脚本运行的当前进程ID号
$! 后台运行的最后一个进程的ID号
$@ 与$*相同,但是使用时加引号,并在引号中返回每个参数。
$- 显示Shell使用的当前选项,与set命令功能相同。
$? 显示最后命令的退出状态。0表示没有错误,其他任何值表明有错误。


5.在函数中使用变量


1)全局变量:

全局变量指的是在shell脚本中任何(定义后)地方都有效的变量,当然作为shell脚本的配置文件变量–环境变量,自然可以被视为全局变量来使用。


使用举例:

#!/bin/bash
function test() {
    #先输出变量 d_o_f
    echo "d_o_f:" $d_o_f 
    #函数内定义的变量 d_i_f 和 d_o_f
    d_i_f="defined in function"
    d_o_f="modified in function"
    #函数内定义后,输出两个变量
    echo "d_i_f:" $d_i_f
    echo "d_o_f:" $d_o_f
}
echo "---out fucntion---"
#函数外部定义变量d_o_f
d_o_f="defined out function"
echo "d_o_f:" $d_o_f
echo "---in function---"
test
echo "---out function---"
echo "d_i_f:" $d_i_f
echo "d_o_f:" $d_o_f

输出:

---out fucntion---

d_o_f: defined out function

---in function---

d_o_f: defined out function

d_i_f: defined in function

d_o_f: modified in function

---out function---

d_i_f: defined in function

d_o_f: modified in function


由上面的输出可以看出:

1、函数内是可以访问全局变量,并且对全局变量的修改会真正改变全局变量的值。

2、函数内定义的变量也是全局变量,也就是说函数外可以访问。


2)局部变量

局部变量比全局变量的作用范围小。在函数中,作为临时变量就没有必要将作用域声明那么广,以免引起意想不到的冲突。 

声明局部变量的方法:(加 local)

local var0

local一般用于局部变量声明,多在在函数内部使用。

1)shell脚本中定义的变量是global的,其作用域从被定义的地方开始,到shell结束或被显示删除的地方为止。

2)shell函数定义的变量默认是global的,其作用域从“函数被调用时执行变量定义的地方”开始,到shell结束或被显示删除处为止。函数定义的变量可以被显示定义成local的,其作用域局限于函数内。但请注意,函数的参数是local的。

3)如果同名,Shell函数定义的local变量会屏蔽脚本定义的global变量。


使用举例:

#!/bin/bash
function test() {
    #设置d_o_f为局部变量
    local d_o_f
    #设置d_i_f为局部变量
    local d_i_f
    #输出变量d_o_f
    echo "d_o_f:" $d_o_f
    #函数内定义变量
    d_i_f="defined in function"
    d_o_f="modified in function"
    echo "d_i_f:" $d_i_f
    echo "d_o_f:" $d_o_f
}
echo "---out fucntion---"
#函数外部定义变量d_o_f
d_o_f="defined out function"
echo "d_o_f:" $d_o_f
echo "---in function---"
test
echo "---out function---"
echo "d_i_f:" $d_i_f
echo "d_o_f:" $d_o_f

输出:

---out fucntion---

d_o_f: defined out function

---in function---

d_o_f:

d_i_f: defined in function

d_o_f: modified in function

---out function---

d_i_f:

d_o_f: defined out function


从结果中可以看出关键词local起作用了。

1、对一个与全局变量同名的局部变量修改不会影响全局变量的值。

2、在函数外不能访问一个局部变量。


二、Shell流程控制


和Java、PHP等语言不一样,sh的流程控制不可为空,如(以下为PHP流程控制写法):

<?php
if (isset($_GET["q"])) {
    search(q);
}
else {
    // 不做任何事情
}

在sh/bash里可不能这么写,如果else分支没有语句执行,就不要写这个else。


1.语句判断


1)判断语句test命令

可以使用:man test查看test的语法说明。


以下为test的几个基本使用:

-f:文件是否存在

-d:目录是否存在

-r:文件是否有读权限

-w:文件是否有写权限

-x:文件是否有执行权限


示例:

#!/bin/bash
filename=/home/zhangsan
test -f $filename && echo 'exist' || 'not exist'

通过./shelltest执行,会显示'not exist'


2)[ ]判断

注意:

· 中括号中必须用空格隔开

· 中括号中的变量最好以双引号括起来

· 中括号中的常数,最好以单引号括起来


示例:

[ "$a" == "$b" ]&&echo 'yes' || echo 'no'
[ '12' == '10' ]&&echo 'yes' || echo 'no'


2.条件分支


三种条件分支:单分支、双分支、多分支

1. if [ 表达式 ] then  语句  fi

2. if [ 表达式 ] then 语句 else 语句 fi

3. if [ 表达式] then 语句  elif[ 表达式 ] then 语句 elif[ 表达式 ] then 语句   …… fi


1)单分支判断

单分支 if 条件语句最为简单,就是只有一个判断条件,如果符合条件则执行某个程序,否则什么事情都不做。语法如下:

if [条件判断式];then

程序

fi

在使用单分支 if 条件查询时需要注意几点:

· if 语句使用 fi 结尾,和一般语言使用大括号结尾不同。

· [条件判断式] 就是使用 test 命令判断,所以中括号和条件判断式之间必须有空格。

· then 后面跟符合条件之后执行的程序,可以放在 [] 之后,用":"分隔;也可以换行写入,就不需要":"了,比如单分支 if 条件语句还可以这样写:

if [条件判断式]

then

程序

fi

单分支 if 条件语句非常简单,但是千万不要小看它,这是流程控制语句最基本的语法。而且在实现 Linux 管理时,我们的管理脚本一般都不复杂,单分支 if 条件语句使用的概率还是很大的。


示例:

#!/bin/bash
filename=/home/asdf
if[ test -f $filename ];then
  echo 'aa'
fi


2)双分支判断

在双分支 if 条件语句中,当条件判断式成立时,则执行某个程序;当条件判断式不成立时,则执行另一个程序。

语法如下:

if [条件判断式]

then

当条件判断式成立时,执行的程序

else

当条件判断式不成立时,执行的另一个程序

fi


示例:

a=10
b=20
if [ $a == $b ]
then
   echo "a is equal to b"
else
   echo "a is not equal to b"
fi

另外:if ... else 语句也可以写成一行,以命令的方式来运行,像这样:

if test $[2*3] -eq $[1+5]; then echo 'The two numbers are equal!'; fi;

其中,test 命令用于检查某个条件是否成立,与方括号([ ])类似。


3)多分支判断

多分支判断有两种方式:if elif else方式、case in方式。


第一种:if elif else方式

在多分支 if 条件语句中,允许执行多次判断。也就是当条件判断式 1 成立时,执行程序 1;当条件判断式 2 成立时,执行程序 2;依次类推,当所有条件不成立时,执行最后的程序。语法如下:

if[条件判断式1]

then

当条件判断式1成立时,执行程序1

elif [条件判断式2]

then

当条件判断式2成立时,执行程序2

…省略更多条件...

else

当所有条件都不成立时,最后执行此程序、

fi


示例:

#!/bin/bash
if[];then
  echo 'aa'
elif
  echo 'bb'
elif
  echo 'cc'
fi


从终端接收一个输入参数,然后进行条件判断。(read:接收用户输入)

#!/bin/bash
echo '输入一个值:'
read number
if[ $number == 1 ];then
  echo '2'
elif[ $number == 2 ];then
  echo '2'
else
  echo '错误'
fi


第二种:case in方式

case 语句和 if...elif...else 语句一样都是多分支条件语句,不过和多分支 if 条件语句不同的是,case 语句只能判断一种条件关系,而 if 语句可以判断多种条件关系。

case 语句的语法如下:

case $变量名 in

"值 1")

;;

如果变量的值等于值1,则执行程序1,值

2")

如果变量的值等于值2,则执行程序2

…省略其他分支…

*)

如果变量的值都不是以上的值,则执行此程序

;;

esac


这条语句需要注意以下内容:

· case 语句会取出变量中的值,然后与语句体中的值逐一比较。如果数值符合,则执行对应的程序;如果数值不符,则依次比较下一个值;如果所有的值都不符合,则执行"*)"("*"代表所有其他值)中的程序。

· case 语句以"case"开头,以"esac"结尾。

在每个分支程序之后要以";;"(双分号)结尾,代表该程序段结束(千万不要忘记)。


示例:

#!/bin/bash
echo '输入一个值:'
read number
case $number in
1)
  echo '1';;
2)
  echo '2';;
*)
  echo '错误';;
esac


注意,多分支 case 条件语句只能判断变量中的值到底是什么,而不能像多分支if语句那样,可以判断多个条件,所以多分支 case 条件语句更加适合单条件多分支的情况。比如,我们在系统中经常看到请选择"yes/no",或在命令的输出中选择是执行第一个选项,还是执行第二个选项(fdisk 命令)。在这些情况下,使用 case 最为适合。我们写一个选择"yes/no"的例子,命令如下:

[root@localhost ~]# vi sh/case.sh
#!/bin/bash
#判断用户输入
read -p "Please choose yes/no: " -t 30 cho
#在屏幕上输出"请选择yes/no",然后把用户选择赋予变量cho
case $cho in
#判断变量cho的值
    "yes")
    #如果是yes
        echo "Your choose is yes!"
        #则执行程序1
        ;;
    "no")
    #如果是no
        echo "Your choose is no!"
        #则执行程序2
        ;;
    *)
    #如果既不是yes,也不是no
    echo "Your choose is error!"
    #则执行此程序
    ;;
esac

解释一下脚本思路:请用户输入 yes 或 no,如果输入的是 yes,则输出"Your choose is yes!";如果输入的是 no,则输出"Your choose is no!";如果输入的是其他字符,则输出"Your choose is error!"。


3.循环语句


循环语句有三种方式:while do循环、until do循环、for循环

说明:[]中要使用以下转义符号;(())不需要转义。shell推荐使用[]。

[] : -eq -ne -gt -ge -lt -le

(()): == != > >= < <=


1)while do循环

while [条件判断式]

do

程序

done

对 while 循环来讲,只要条件判断式成立,循环就会一直进行,直到条件判断式不成立,循环才会停止。

示例:

说明:示例中[ $i -eq 5 ] 等价于 (($i==5))。

#!/bin/bash
int=1
while(( $int<=5 ))
do
    echo $int
    let "int++"
done

输出:

1

2

3

4

5


2)until do循环

再来看看 unti 循环,和 while 循环相反,只要条件判断式不成立,则进行循环,并执行循环程序;一旦条件判断式成立,则中止循环。语法如下:

until [条件判断式]

do

程序

done


示例:

#!/bin/bash
i=10
until (($i<5));do
  echo $i;
  ((i--));
done;

输出:

10

9

8

7

6

5

until 循环执行一系列命令直至条件为 true 时停止。until 循环与 while 循环在处理方式上刚好相反。    


3)for循环

语法一

for 变量 in 值1 值2 值3…

do

程序

done

在这种语法中,for 循环的次数取决于 in 后面值的个数(以空格分隔),有几个值就循环几次,并且每次循环都把值赋予变量。也就是说,假设 in 后面有三个值,for 会循环三次,第一次循环会把值 1 赋予变量,第二次循环会把值 2 赋予变量,以此类推。

示例:

#!/bin/bash
for loop in 1 2 3 4 5
do
    echo "The value is: $loop"
done


语法二

for ((初始值;循环控制条件;变量变化))

do

程序

done

在语法二中需要注意以下几点:

· 初始值:在循环开始时,需要给某个变量赋予初始值,如 i=1。

· 循环控制条件:用于指定变量循环的次数,如 i<=100,则只要 i 的值小于等于 100,循环就会继续。

· 变量变化:每次循环之后,变量该如何变化,如 i=i+1,代表每次循环之后,变量的值都加 1。

#!/bin/bash
for((i=1;i<=10;i++));do
  echo $i
done;

注意:列表是一组值(数字、字符串等)组成的序列,每个值通过空格分隔。每循环一次,就将列表中的下一个值赋给变量。    


4.exit、break、continue 循环控制  


系统中是有 exit 命令的,用于退出当前用户的登录状态。但是在 Shell 脚本中,exit 语句是用来退出当前脚本的。也就是说,在 Shell 脚本中,只要碰到了 exit 语句,后续的程序就不再执行,而直接退出脚本。exit 的语法如下:

exit [返回值]

如果在 exit 之后定义了返回值,那么这个脚本执行之后的返回值就是我们自己定义的返回值。可以通过查询 $? 这个变量来査看返回值。如果 exit 之后没有定义返回值,则脚本执行之后的返回值是执行 exit 语句之前最后执行的一条命令的返回值。写一个 exit 语句的例子:

[root@localhost ~]#vi sh/exit.sh

#!/bin/bash
#演示exit的作用
read -p "Please input a number:" -t 30 num
#接收用户的输入,并把输入赋予变量num
y=$(echo $num|sed's/[0-9]//g')
#如果变量num的值是数字,则把num的值替换为空;否则不替换
#把替换之后的值赋予变量y
[-n "$y" ] && echo "Error! Please input a number!" && exit 18
#判断变量y的值,如果不为空,则输出报错信息,退出脚本,退出返回值为18
echo The number is: $num"
#如果没有退出脚本,则打印变量num中的数字

在这个脚本中,大家需要思考,如果输入的不是数字,那么"echo"The number is:$num""这条命令是否会执行?当然不会,因为如果输入的不是数字,那么"[-n"$y"]&&echo"Error! Please input a number!"&&exit 18"这条命令就会执行,exit 一旦执行,脚本就会中止。运行一下这个脚本:

[root@localhost ~]# chmod 755 sh/exit.sh
#给脚本赋予执行权限
[root@localhost ~]# sh/exit.sh
#执行脚本
Please input a number: test
#输入值不是数字,而是test
Error! Please input a number!
输出报错信息,而不会输出test
[root@localhost ~]# echo $?
#查看一下返回值
18
#返回值居然是18
[root@localhost ~]# sh/exit.sh
Please input a number: 10
#输入数字10
The number is: 10
#输出数字10


break语句

当程序执行到 break 语句时,会结束整个当前循环。而 continue 语句也是结束循环的语句,不过 continue 语句只会结束单次当前循环,继续下次循环。我们画一张示意图解释一下 break 语句,如图 1 所示。

2-1Q022154J6338.jpg

【例 1】

[root@localhost ~]# vi sh/break.sh

#!/bin/bash
#演示break眺出循环
for ((i=1;i<=10;i=i+1))
#循环10次
    do
        if ["$i" -eq 4]
        #如果变量 i 的值等于4
        then
        break
        #则退出整个循环
        fi
        echo $i
        #输出变量i的值
    done

运行一下这个脚本,因为一旦变量的值等于 4,整个循环就会跳出,所以应该只能循环 3 次。

[root@localhost ~]# chmod 755 sh/break.sh
[root@localhost ~]# sh/break.sh
1
2
3


continue语句

再来看看 continue 语句,它也是结束循环的语句,但它只单次当前循环。我们也画一张示意图来说明一下 continue 语句,如图 2 所示。

2-1Q022155P5951.jpg

还是用刚刚的脚本,不过退出语句换成 continue 语句,看看会发生什么情况。


运行一下这个脚本:

[root@localhost ~]# chmod 755 sh/continue.sh
#赋予执行权限
[root@localhost ~]# sh/continue.sh
1
2
3
5
#少了4这个输出
6
7
8
9
10

continue 语句只会退出单次当前循环,并不会影响后续的循环,所有只少 4 这个输出。


参考网址:

https://www.jb51.net/article/57951.htm 

https://www.cnblogs.com/YankaiJY/p/8832436.html 

http://www.runoob.com/linux/linux-shell-func.html

http://www.runoob.com/linux/linux-shell-process-control.html 

https://blog.csdn.net/zbw18297786698/article/details/77802037 

https://blog.csdn.net/timo1160139211/article/details/77165861 

https://blog.csdn.net/apollon_krj/article/details/70148022 


转载请注明: ITTXX.CN--分享互联网 » Shell&Shell脚本基础教程——函数和流程控制

最后更新:2018-12-24 12:44:04

赞 (2) or 分享 ()
游客 发表我的评论   换个身份
取消评论

表情
(0)个小伙伴在吐槽