Linux Shell之七 函数应用

函数是什么?

    函数是一些命令的集合,使用一个名称做代表,称为函数名称。函数名称的命名规则和变量相同。

    一旦函数定义好了,执行这个名称,就好象执行Bash的命令一样,称为调用函数。实际上,Bash调用函数时,会执行函数里的命令区域,执行

完毕,Bash会回到调用函数的下一行继续执行。

    函数的最大作用是可以让程序模块化。如果Script程序中,需要重复执行某一命令区域,那么就应当使用函数代表这个区域,一方面可使程序精简,一方面程序代码页比较容易维护。

一、函数的用法

1、函数的语法

语法1:

function 函数名称()

{

   命令区域

}

函数名称与()之间可以直接相连,也可用空格隔开。

语法2:

函数名称()

{

   命令区域

}

关键词function可省略

语法3:

function 函数名称

{

   命令区域

}

如果使用关键词function,函数名称后的()也可省略

例子:

#!/bin/bash

getline ()          #定义函数getline,用来定义文件行数

{

 local i=0          #i代表已计算的行数,先归0。               

    #local用来设定变量i是getline函数中专有的变量,不影响script其它地方也叫i的函数

 while read line                          

 do                 #使用while循环,自变量值$file指定文件读取每一行

  let ++i           #每读一行 变量i值+1

 done < $file       #使用转向输入,让read能由$file读取数据

 echo "$file文件共有$i行"   #显示总行

}


file=$1             #由命令行第一个参数,取得要计算行数的文件名。

getline             #调用getline函数

echo "getline 执行完毕"   #getline执行完后,回到这里继续执行下一指令。

#./script passwd

passwd文件共有36行

getline执行完毕

在调用函数之前一定要先定义该函数。

unset -f 函数  取消函数

2、函数的结束状态

执行函数时,函数中最后一个命令的传回值代表函数的结束状态。执行函数如果遇到return命令,就立即结束,回到调用函数的下一个命令,此时函数的传回值为0

#!/bin/bash

getline ()

{

local i=0

while read line

do 

  let ++i

  if (($i > 10));then        #判断是否超过10行

    echo "$file文件大于10行,不再继续"

    return                   #遇到return命令,立即回到echo$?所在行

     #默认传回值为0,也可指定不同的传回值,直接在return空格加数字即可

  fi

done < $file

echo "$file文件共有$i行"

}


file=$1

getline

echo $?

echo "getline 执行完毕"


可以根据$?(return 接的数字n )的值执行想要的命令,如上  if[ $? -eq 3 ];then

                                                 echo "行数过多,放弃读取"

                                                 else

                                                 echo 'getline执行完毕'

                                                 fi

二、函数与变量的作用范围。

1、函数的作用范围

函数仅在定义的shell环境中有效,Bash执行函数时,并不会另外再开启一个子shell。

如果要传递函数给shell环境使用,可以用内置命令export   -f函数名称,这样此函数就变成了环境变量的一部分(函数型),可供子shell的script调用。

2、变量的作用范围

如果没有特别的设定变量的属性,那么在Script中自定义的变量称为全局变量(对此脚本而言)。作用范围在整个Script文件中皆有效。

#!/bin/bash

getline ()

{

local i=0               #这就定义了变量i只在函数getline中有效,变量i和函数外其它叫i的变量完全不一样。

while read line

do 

....

三、位置参数

1、命令行的位置参数

$0   表示脚本名 $1 表示第一个参数 $2表示第2给参数 $(10)表示第10个参数

$*    代表所有的位置参数,看为一个字符串。1.sh a x y则$*为"a x y"

$@    代表所有以空白隔开的参数,各位置串行。    1.ah a x y则$@为"a"、"x"、"y"

$#    位置参数的个数,1.ah a x y则$#的值为3

#!/bin/bash

if [ $# -ne 2 ];then                必须键入2个参数,否则错误退出

  echo "使用方法:./$0 参数1 参数2"

  exit 1

fi 

2、移动位置参数

Bash的内置命令shift可以往前移动位置参数的值,语法如下:

shift n 

n为正整数,代表往前移动的次数。n可以省略不写代表移动一次。执行 shift n,$(n+1)的值会放入$1

以执行shift命令来说(不指定次数),$2的值放入$1,$3的值放入$2,$4的值放入$3,,,如果一直执行shift(次数>=n),会把所有的位置参数清空

shift 一次清除1个(从$1开始) ,shift 2 一次清除2个

1
2
3
4
5
6
7
8
9
10
11
12
13
#!/bin/bash
echo "\$@的初始值为$@"
while shift
do
[ -n "$1" ] && echo "shift 1次,\$@的变化:$@"
done
执行结果:
[root@centos tmp]# bash 1.sh  a b c d e 
$@的初始值为a b c d e
shift 1次,$@的变化:b c d e
shift 1次,$@的变化:c d e
shift 1次,$@的变化:d e
shift 1次,$@的变化:e

3、指定位置参数的值

指定位置参数的值称为重置(reset),用Bash命令set

1
2
3
4
5
6
7
8
9
10
11
12
13
14
#!/bin/bash
declare -i i=0
set 10 20 30 40 50
 for in $@
 do
 ((i++))
 echo " 第 $i 个位置参数 $$i = $p"     #$$目前bash shell的进程编号  
done
[root@centos tmp]# bash 2.sh 
 第 1 个位置参数 3547i = 10
 第 2 个位置参数 3547i = 20
 第 3 个位置参数 3547i = 30
 第 4 个位置参数 3547i = 40
 第 5 个位置参数 3547i = 50

一旦用set重置位置参数,其原有的值就会消失,改以新值取代。(无论输入几个参数,set设置几个就是几个)

如果要一次重置所有参数,使其值为空,可执行 set --

4、取用命令行的选项和参数

在设计脚本的时候,往往需要由命令行中取得用户提供的选项和参数,根据不同的选项,脚本有不同的处理方式和执行结果。选项的使用方式可以

是单一选项,也可以在选项后方加上准备作用的参数,而且,选项出现的次序并没有严格的要求。

如以下例子:

./script -u jacken -a -h

或改用以下形式

./script -a -u jacken -h

如果要想取得这些选项和参数,使用前述的位置参数也是可以的,不过拿到位置参数后,必须再做许多条件判断才行,因为选项可能以不同的次序

出现在命令行不同的位置,情况十分复杂。解决这样的问题,可改用Bash提供的内置命令getopts。

getopts语法如下:

getopts 选项行 选项变量

其中选项行,是由各选项的单一字符组成,如前述例子中用来3个选项,可组合成“u:ah”

如果某一个选项字符后方,接上":" 则表示该选项需要提供一个参数,如这里的u后面有":"

如果执行脚本的时候,选项u后方没有提供额外的参数,那么Bash就会显示“option requires an argument --u”的错误信息。

如果不想出现这种错误信息,可在选项行最前面加上":" 如 ":u:ah" 像这样子,u后边没有参数也不会报错了。

至于选项变量的作用是:

getopts由命令行取得选项,把它放入选项变量中,如果该选项需要额外的参数,参数值会放入OPTARG这个变量中。

例子:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
[root@Shell ~]# ./opt.sh -a
提供了选项a
[root@Shell ~]# ./opt.sh -h
提供了选项h
[root@Shell ~]# ./opt.sh -a -h
提供了选项a
提供了选项h
[root@Shell ~]# ./opt.sh -u
./opt.sh: option requires an argument -- u
[root@Shell ~]# ./opt.sh -u hello
提供了选项-u和参数:hello
[root@Shell ~]# cat opt.sh 
#!/bin/bash
#
while getopts u:ah opt
do
  case $opt in
  u)
  echo "提供了选项-u和参数:$OPTARG";;
  a)
  echo "提供了选项a";;
  h)
  echo "提供了选项h";;
  *)
    ;;
  esac
done
[root@Shell ~]#

四、建立函数库

如果某些函数经常出现在设计的script中,可以考虑把这些函数抽出来,集中存成一个文件,但这个文件称为函数库。

在命名函数时,函数名称第一个字符使用_(下划线),通常这就代表系统用的函数或变量名称。

在/tmp下建立函数库mylib1.sh

_getip()

{

  local tmp r ip                           #函数内部使用的变量设为私有

[ -z "$1" ] && return                      #如果位置参数$1为空,直接退出 

shuzu=()                                   #建立数组变量shuzu,作为传回ip字符串用,初始值设为空数组

tmp=$(ifconfig $1 | grep 'inet addr')           

r=${tmp/inet addr:/}

ip=${r/Bcast*/}

shuzu=($ip)                                #将找到的ip设为第一个数组元素,作为函数处理结果的传回值

}

调用函数数据库的语法,. /路径/函数数据库   .也用source来表示

#!/bin/bash

MYLIB_DIR="/tmp"                           #设置函数库默认路径

if [ ! -d "MYLIB_DIR" ];then

   MYLIB_DIR="."                           #如果默认路径不存在就设为当前目录

fi

. $MYLIB_DIR/mylib1.sh                     #调用函数库mylib1.sh

_getip eth0                                #执行_getip传入的参数是网络接口的名称eth0

ip=${shuzu[0]}                             #取出代表函数执行结果的数组变量shuzu的第一个元素,设值给变量ip

if [ -n "$ip" ];then                       #判断$ip是否为空,-z 为空 -n不为空

   echo "主机ip是:$ip"

else

   echo "找不到IP"

fi



本文转自Jacken_yang 51CTO博客,原文链接:http://blog.51cto.com/linuxnote/1641215,如需转载请自行联系原作者

上一篇:Mac 下 Brew 安装 Node


下一篇:oracle信息统计脚本runstats的创建与验证