《Linux命令行与shell脚本编程大全》第十七章 创建函数

可以将shell脚本代码放进函数中封装起来,这样就能在脚本中的任何地方多次使用它了。

17.1 基本的脚本函数

函数:是一个脚本代码块,可以为其命名并在代码中任何位置重用。

17.1.1 创建函数

有两种格式:name 是函数名

1)

function name

{

         commands

}

2)这种就比较接近c语言风格了

name()

{

         commands

}

17.1.2 使用函数

跟其他shell命令一样,在行中指定函数名就好了。

在函数定义前使用函数,会收到一条错误消息。

函数名是唯一的,如果重定义了函数,新的会覆盖旧的,并且不会产生任何错误消息。

例子:

   1 #!/bin/bash
   2 
   3 function fun
   4 {
   5         echo "hahahaha, i am a function"
   6 }
   7 
   8 count=1
   9 while [ $count -lt 5 ]
  10 do
  11         fun
  12         count=$[ $count + 1 ]
  13 done
  14 
  15 fun2  # Error fun2 not define
  16 fun2() # 声明函数的另外一种方式
  17 {
  18         echo "I am Fun2, hahaha"
  19 }
  20 fun2
 

17.2 返回值

函数运行结束会返回一个退出状态码,有3种方法为函数生成退出状态码。

17.2.1 默认退出状态码

在函数结束时用 $? 来确定函数的退出状态码。

比如:

fun

echo “return code:$?”

如果函数最后执行的语句失败了,这里就会返回非0,最后成功了(不管前面有没有失败)返回都是0.

17.2.2 使用return命令

bashshell使用return命令来退出函数并返回特定的退出状态码。return允许指定一个整数值来定义函数的退出状态码。

注意:

函数一结束就要立即取返回值

退出状态码必须是0 – 255.(大于255会产生一个错误值)

17.2.3 使用函数输出

可以将函数输出(任何类型的函数输出)保存到shell变量中。

语法:result=$(fun) 这个命令会将fun函数的输出赋给$result变量

例子:

   1 #!/bin/bash
   2 
   3 function fun
   4 {
   5         echo "hahahaha, i am a function"
   6         return 1
   7 }
   8 
   9 fun
  10 echo "fun return $?"
  11 
  12 function fun2
  13 {
  14         echo "This is Function fun2"
  15         read -p "Enter a value:" num
  16         echo $[ $num * 2 ]
  17 }
  18 
  19 #fun2 # 如果加上这句就会调两次了。
  20 result=$(fun2)
  21 echo "fun2 return:$result"
 

 这样就可以返回浮点数和字符串了。

17.3 在函数中使用变量

介绍一些处理shell脚本函数内外变量的方法

17.3.1 向函数传递参数

就跟向脚本传递参数一样,可以用$# $0 $1 $2

注意脚本主体的$1 $2 和传到函数里面的并不相同。

例子:

   1 #!/bin/bash
   2 function add
   3 {
   4         if [ $# -eq 0 ] || [ $# -gt 2 ]
   5         then
   6                 echo -1
   7         elif [ $# -eq 1 ]
   8         then
   9                 echo $[ $1 + $1 ]
  10         else
  11                 echo $[ $1 + $2 ]
  12         fi
  13 }
  14 
  15 #ret=$(add)
  16 #ret=$(add 34) # 这里说明的如何传入参数
  17 ret=$(add 23 18)
  18 if [ $ret -eq -1 ]
  19 then
  20         echo "Function add Error"
  21 else
  22         echo "The value = $ret"
  23 fi
  24 
  25 if [ $# -eq 2 ] # 这个的脚本主体接收的参数个数
  26 then
  27         echo "The value is $(add $1 $2)" # 将脚本主体的参数传给里面的函数
  28 else
  29         echo "Input Error"
  30 fi
 

17.3.2 在函数中处理变量

变量的作用域比较麻烦。作用域是变量可见的区域。

函数中定义的变量和普通变量的作用域不同,也就是说对脚本的其他部分来说它们是隐藏的

函数使用两种类型的变量:全局变量和局部变量

1.全局变量

是指在shell脚本中任何地方都有效的变量。

在脚本主体部分定义了全局变量,那么在函数内可以读取它的值。

在函数内定义了全局变量,在脚本的主体部分也可以读取它的值。

默认情况下,在脚本中定义的任何变量都是全局变量。函数外定义的变量可在函数内访问

这样要特别注意变量的使用。很容易就改变了变量。

2.局部变量

可以在函数内部使用的任何变量都声明成局部变量。

在变量声明前加上local关键字就好了

local temp

例子:

   1 #!/bin/bash
   2 function fun
   3 {
   4         #temp=$[ $value + 5 ] # 如果这个是全局变量下面的结果就会异常
   5         local temp=$[ $value + 5 ] 
   6         ret=$[ $temp * 2 ]
   7 }
   8 
   9 temp=4
  10 value=6
  11 fun
  12 echo "fun: ret = $ret"
  13 if [ $temp -gt $value ]
  14 then
  15         echo "temp is big"
  16 else
  17         echo "value is big"
  18 fi
 

17.4 数组变量和函数

第6章讨论了数组来在单个变量中保存多个值的高级用法

17.4.1 向函数传数组参数

复习一下数组的用法:

定义方法1:初始化数组 array=(a b c)

定义方法2:新建数组并添加原色  array[数组]=元素

定义方法3:将命令输出作为数组元素 array=($(command))

数组操作:

1)获取所有元素:echo ${array[*]}

2)获取第n个元素: echo ${array[n]}    n为数组下标

3)添加元素:array[3]=d

4)删除元素:unset array[n] n为数组下标

1. 数组作为参数传递时不能用 $arrayName。

应该这样: fun ${arrName[*]}

还可以加上双引号。

例子:

   1 #!/bin/bash
   2 function testit
   3 {
   4         echo "The param are:$@, Param count:$#"
   5         thisarray=$1
   6         echo "The received array is:${thisarray[*]}"
   7 
   8         for param in "$@"
   9         do
  10                 echo "Param = $param"
  11         done
  12 }
  13 
  14 myarray=(13 25 35 45 55 65)
  15 echo "The original array is: ${myarray[*]}"
  16 testit "${myarray[*]}"
  17 testit ${myarray[*]}
 

 有双引号时,函数接受的参数个数为1.

17.4.2 从函数返回参数

函数用echo语句来按正确顺序输出单个数组值,然后脚本再将它们重新放进一个新的数组变量中。

例子:

   1 #!/bin/bash
   2 function fun
   3 {
   4         local origarray
   5         local newarray
   6         local count
   7         local i
   8         origarray=($(echo "$@"))
   9         newarray=($(echo "$@"))
  10         count=$[ $# - 1 ]
  11         for (( i = 0; i <= count; i++ ))
  12         {
  13                 newarray[$i]=$[ ${origarray[$i]} * 2 ]
  14         }
  15         echo ${newarray[*]}
  16 }
  17 
  18 myarr=(1 2 3 4 5 6 7 8 9 10 11 12 13 14)
  19 echo "original arr is: ${myarr[*]}"
  20 arg1=$(echo ${myarr[*]}) # 这里的用命令输出定义数组
  21 ret=($(fun $arg1))
  22 echo "new arr is: ${ret[*]}"
 

用arg1变量将数组值传给函数fun。函数将该数组重组到新的数组变量中。

脚本用fun函数的输出来重新生成一个新的数组变量

17.5 函数递归

函数的返回值直接用echo传递了。

例子:求阶乘(注意书上的例子p369 中间部分的 result ** 写错了)

   1 #!/bin/bash
   2 function fun1
   3 {
   4         if [ $1 -eq 1 ]
   5         then
   6                 echo 1
   7         else
   8                 local temp=$[ $1 - 1 ]
   9                 local ret=$(fun1 $temp)
  10                 echo $[ $ret * $1 ]
  11         fi
  12 }
  13 
  14 read -p "Enter value:" value
  15 ret=$(fun1 $value)
  16 echo "ret = $ret"
 

17.6 创建库

允许创建函数库文件,然后在多个脚本中引用该库文件。

假设有个脚本,myfuncs。里面定义了一些函数:

  1 function addem
   2 {
   3         echo $[ $1 + $2 ]
   4 }
   5 
   6 function multem
   7 {
   8         echo $[ $1 * $2 ]
   9 }
  10 
  11 
  12 function divem
  13 {
  14         if [ $2 -ne 0 ]
  15         then
  16                 echo $[ $1 / $2 ]
  17         else
  18                 echo -1
  19         fi
  20 }
 

shell函数仅在定义它的shell会话中有效。

如果你在shell命令行界面的提示符下运行myfuncs shell脚本,shell会创建一个新的shell并在其中运行这个脚本。

它会为那个新的shell定义这里面的函数,但当你运行另外一个要用到这些函数的脚本时,它们是无法使用的。

如何使用:使用函数库的关键在于source命令,source命令会在当前的shell上下文中执行命令。而不是创建一个新的shell。

source命令有个快捷的别名,称作点操作符。

如何使用: . ./myfuncs

这里假定在同一目录,如果不在,则需要指定相应的路径名。

实例:

 1 #!/bin/bash
   2 . ./myfuncs
   3 
   4 value1=10
   5 value2=5
   6 echo "Add Test ret = $(addem $value1 $value2)"
   7 echo "Mult Test ret = $(multem $value1 $value2)"
   8 echo "Div Test ret = $(divem $value1 $value2)"
 

17.7 在命令行上使用函数

17.7.1 在命令行上创建函数

可以在命令行界面的提示符下直接使用函数。

用起来就跟命令一样。而且一旦定义的函数,就可以在整个系统中使用它了,不需要管PATH环境变量了。

例子:

注意:

1)必须在每个命令后面加上分号,这样才能知道哪里是命令的起止

2)不能创建跟内建命令或其他命令相同的函数,否则会覆盖原来的命令

17.7.2 在.bashrc文件中定义函数

在命令行数定义shell函数明显的缺点是退出shell时,函数就消失了。

解决方法:将函数定义在一个特定的位置,这个位置在每次启动一个新的shell的时候都由shell重新载入。

最佳地点就是.bashrc。bash shell在每次启动时都会在主目录查找这个文件

1. 直接定义函数

直接在.bashrc后面加上

function addem

{

         echo $[ $1 + $2 ]

}

这样在系统上任意地方使用这个函数了。

2.读取函数文件

可以用source命令将库文件中的函数添加到.bashrc中

直接在.bashrc后面加上

.  /home/xcy/myfuncs

这样就可以用myfuncs里面的函数了。

17.8 实例

本节介绍GNU shtool shell 脚本函数库。shtool库提供了一些简单的shell脚本库。这里暂时不写了。

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏后端技术探索

实用篇-无处不在的Location

location配置是nginx模块化配置中最出色的一个设计,几乎所有nginx的业务场景都要通过书写多个location配置来顺应业务需要。语法配置和执行规则...

1152
来自专栏java一日一条

JVM 进行线程同步背后的原理

所有的 Java 程序都会被翻译为包含字节码的 class 文件,字节码是 JVM 的机器语言。这篇文章将阐述 JVM 是如何处理线程同步以及相关的字节码。

771
来自专栏青玉伏案

窥探Swift编程之错误处理与异常抛出

在Swift 2.0版本中,Swift语言对其错误处理进行了新的设计,当然了,重新设计后的结果使得该错误处理系统用起来更爽。今天博客的主题就是系统的搞一下Swi...

1955
来自专栏Linyb极客之路

深入理解和探究Java类加载机制

java.lang.ClassLoader类的基本职责就是根据一个指定的类的名称,找到或者生成其对应的字节代码,然后从这些字节代码中定义出一个Java 类,即 ...

1043
来自专栏Deep learning进阶路

C++随记(一)---字符串数组的输入问题

首先来看一段程序: #include<iostream> using namespace std; int main(){ char name[10],s...

1980
来自专栏开源优测

移动测试Appium之API手册

移动测试Appium之API手册 前言 本文对Appium Python Client中webdriver.py代码进行分析说明。 笔者使用python3.6版...

3999
来自专栏xingoo, 一个梦想做发明家的程序员

数字按照不同格式转换成字符串

  如果自己写函数,不使用itoa怎么判断呢?   我们用通常的办法,对数字进行每位的除商,得到后与字符'0'相加。 flag = 0; ...

20710
来自专栏WebDeveloper

php缓冲区与header函数之间的秘密

我们在实际的开发中,是否听说过在header之前不能有任何的实际输出。甚至有的认为header函数必须写在代码的最前面。可是你是否试验过header函数之前输出...

1232
来自专栏Python

浅淡python中with的用法,上下文管理器

例子一 首先来看一段代码: class Foo(object): def __init__(self): print('实例化一个对象...

21810
来自专栏Nian糕的私人厨房

JavaScript 分支/循环语句

if...else 语句,在条件为 true 时执行代码,在条件为 false 时执行其他代码

874

扫码关注云+社区

领取腾讯云代金券