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,如需转载请自行联系原作者

相关文章
|
1天前
|
网络协议 Shell Linux
LabVIEW 在NI Linux实时设备上访问Shell
LabVIEW 在NI Linux实时设备上访问Shell
|
1天前
|
Linux 编译器 调度
xenomai内核解析--双核系统调用(二)--应用如何区分xenomai/linux系统调用或服务
本文介绍了如何将POSIX应用程序编译为在Xenomai实时内核上运行的程序。
16 1
xenomai内核解析--双核系统调用(二)--应用如何区分xenomai/linux系统调用或服务
|
2天前
|
消息中间件 存储 Linux
linux实时应用如何printf输出不影响实时性?
本文探讨了Linux实时任务中为何不能直接使用`printf(3)`,并介绍了实现不影响实时性的解决方案。实时任务的执行时间必须确定且短,但`printf(3)`的延迟取决于多个因素,包括用户态glibc缓冲、内核态TTY驱动和硬件。为确保实时性,通常将非实时IO操作交给低优先级任务处理,通过实时进程间通信传递信息。然而,即使这样,`printf(3)`在glibc中的实现仍可能导致高优先级任务阻塞。Xenomai 3提供了一个实时的`printf()`实现,通过libcobalt库在应用编译链接时自动处理,预分配内存,使用共享内存和线程特有数据来提高效率和实时性。
12 0
linux实时应用如何printf输出不影响实时性?
|
2天前
|
Shell Linux
【Linux】进程实践项目(更新中) — 自主shell编写
前几篇文章,我们学习进程的相关知识:进程概念,进程替换,进程控制。熟悉了进程到底是个什么事情,接下来我们来做一个实践,来运用我们所学的相关知识。这个项目就是手搓一个shell模块,模拟实现Xshell中的命令行输入。
9 1
|
3天前
|
Shell Linux 信息无障碍
5 个有用的 Linux Shell 转义序列
5 个有用的 Linux Shell 转义序列
|
3天前
|
存储 算法 网络协议
【探索Linux】P.26(网络编程套接字基本概念—— socket编程接口 | socket编程接口相关函数详细介绍 )
【探索Linux】P.26(网络编程套接字基本概念—— socket编程接口 | socket编程接口相关函数详细介绍 )
11 0
|
4天前
|
消息中间件 Unix Linux
【探索Linux】P.14(进程间通信 | 匿名管道 | |进程池 | pipe() 函数 | mkfifo() 函数)
【探索Linux】P.14(进程间通信 | 匿名管道 | |进程池 | pipe() 函数 | mkfifo() 函数)
10 0
|
4天前
|
Linux Shell
Linux中system函数
Linux中system函数
7 0
|
4天前
|
安全 Linux Shell
Linux常用命令详解与实战应用
【5月更文挑战第7天】本文详述了Linux常用命令,包括文件与目录操作(ls, cd, pwd, cp, mv, rm)、文本处理(cat, grep, sed)及系统管理(top, df, du)命令。通过实例演示了如何使用这些命令,帮助读者理解和掌握Linux操作,提升系统管理效率。学习和熟练运用这些基础命令,是高效使用Linux的关键。
|
4天前
|
Shell Linux 编译器
C语言,Linux,静态库编写方法,makefile与shell脚本的关系。
总结:C语言在Linux上编写静态库时,通常会使用Makefile来管理编译和链接过程,以及Shell脚本来自动化构建任务。Makefile包含了编译规则和链接信息,而Shell脚本可以调用Makefile以及其他构建工具来构建项目。这种组合可以大大简化编译和构建过程,使代码更易于维护和分发。
21 5