十二、函数
函数的定义
将shell脚本代码放进代码块封装便于其他地方调用,这样的代码块就叫函数。
创建函数
第一种方式
使用关键字function,后跟函数名,在脚本中函数名必须唯一,如果重复,那么后续的函数会重写前面的函数
function name { commands }
第二种方式
name() {
commands
}
使用函数
在脚本行中指定函数名即可
[root@tzPC 17Unit]# cat test1.sh #!/bin/bash #using a function in a script function func1 { echo "This is an example of a function" } count=1 while [ $count -le 5 ] do func1 count=$[ $count + 1 ] done
返回值
函数的退出状态码是函数中最后一条命令返回的退出状态码,可以使用$?来查看。
$?为0便是命令正常执行,其他值表示命令执行有误。
[root@tzPC 17Unit]# cat test4.sh #!/bin/bash #testing the exit status of a function func1() { echo "trying to display a non-existent file" ls -l badfile } echo "testing the function:" func1 echo "The exit status is:$?" [root@tzPC 17Unit]# bash test4.sh testing the function: trying to display a non-existent file ls: cannot access badfile: No such file or directory The exit status is:2
return命令返回特定退出状态码
return命令可以返回一个特定的整数值来定义函数的退出状态码。
[root@tzPC 17Unit]# cat test5.sh #!/bin/bash #using the return command in a function function db1 { read -p "Enter a value: " value echo "doubling the value" return $[ $value * 2 ] } db1 echo "The new value is $?" [root@tzPC 17Unit]# bash test5.sh Enter a value: 50 doubling the value The new value is 100
需要注意两点:
- 函数一结束就要取返回值,以免被其他命令执行结果覆盖了当前函数的返回值
- 退出状态码取值范围0~255
为什么$?取值不能大于255
答案:https://baijiahao.baidu.com/s?id=1592296182804783596&wfr=spider&for=pc
使用函数输出
使用$(函数名)或者`函数名`获取函数的输出
这里书中有误把反引号打成单引号
[root@tzPC 17Unit]# bash test5b.sh Enter a value: 200 Enter a value: 200 The new value is 400 and 400 [root@tzPC 17Unit]# cat test5b.sh #!/bin/bash #using the echo to return a value function db1 { read -p "Enter a value: " value echo $[ value * 2 ] } result=`db1` result2=$(db1) echo "The new value is $result and $result2"
向函数传递参数
函数可以使用标准的参数环境变量表示命令行上传给函数的参数。
如函数命令行上的任何参数都可以通过$1、$2定义,$#判断函数参数的总数
必须把参数和函数放在同一行上,如
funcl $value1 10
举例
[root@tzPC 17Unit]# cat test6.sh #!/bin/bash #passing parameters to a function function addem { if [ $# -eq 0 ] || [ $# -gt 2 ] then echo -1 elif [ $# -eq 1 ] then echo $[ $1 + $1 ] else echo $[ $1 + $2 ] fi } echo -n "Adding 10 and 15: " #传递两个参数,函数使他相加 value=$(addem 10 15) echo $value echo -n "Let's try adding just one number: " #传递一个参数,函数使他自己加自己 value=$(addem) echo $value echo -n "Finally, try adding three numbers: " value=$(addem 10 15 20) #传递三个参数,函数直接输出-1 echo $value [root@tzPC 17Unit]# bash test6.sh Adding 10 and 15: 25 Let's try adding just one number: -1 Finally, try adding three numbers: -1
在函数中使用脚本传递过来的参数
[root@tzPC 17Unit]# cat test7.sh #!/bin/bash #trying to access script parameters inside a function function func7 { echo $[ $1 * $2 ] } if [ $# -eq 2 ] then value=$(func7 $1 $2) #传递脚本命令行上的参数 echo "The result is $value" else echo "Usage: badtest1 a b" fi [root@tzPC 17Unit]# bash test7.sh 10 15 The result is 150
在函数中处理变量
函数中使用两种类型的变量
- 全局变量
- 局部变量
全局变量是shell脚本中任何地方都有效的变量。
默认情况下,在脚本中定义的任何变量都是全局变量。在函数外定义的变量可在函数内访问。
局部变量是函数内部使用的变量,声明格式如下
local temp local temp=$[ $value + 5 ]
这样如果脚本中在该函数之外有同样名字的变量,他们的值是不会影响到对方的。
[root@tzPC 17Unit]# cat test9.sh #!/bin/bash #demonstrating the local keyword function func1 { local temp=$[ $value + 5 ] result=$[ $temp * 2 ] } temp=4 value=6 func1 #调用函数 echo "The result is $result" if [ $temp -gt $value ] #这里的值使用的是函数外定义的值即4>6 then echo "temp is larger" else echo "temp is smaller" fi [root@tzPC 17Unit]# bash test9.sh The result is 22 temp is smaller
向函数传数组
如果把数组直接作为函数参数,函数只会读取数组变量的第一个值。
这个脚本在书中有两处错误,具体写法如下
[root@tzPC 17Unit]# cat test10.sh #!/bin/bash #array variable to function test function testit { local newarray newarray=`echo "$@"`
#接收传来的参数全部赋值给局部变量newarray,注意这里是反引号
#也可以写成newarray=$(echo "$@") echo "The new array value is: ${newarray[*]}" } myarray=(1 2 3 4 5) echo "The original array is ${myarray[*]}"
#${myarray[*]}的值是 1 2 3 4 5 testit ${myarray[*]}
#向函数传递数组的值,也就是1 2 3 4 5 [root@tzPC 17Unit]# bash test10.sh The original array is 1 2 3 4 5 The new array value is: 1 2 3 4 5
也可以在函数中通过遍历累加数组
[root@tzPC 17Unit]# cat test11.sh #!/bin/bash #adding values in an array function addarray { local sum=0 local newarray newarray=$(echo "$@") #这里也可以写成newarray=`echo "$@"` for value in ${newarray[*]} do sum=$[ $sum + $value ] #将数组的值遍历出来相加 done echo $sum } myarray=(1 2 3 4 5) echo "The original array is: ${myarray[*]}" arg1=$(echo ${myarray[*]}) #将1 2 3 4 5赋值给arg1变量 echo $arg1 result=$(addarray $arg1) echo "The result is $result" [root@tzPC 17Unit]# bash test11.sh The original array is: 1 2 3 4 5 1 2 3 4 5 The result is 15
从函数返回数组
将数组传进函数,再从函数做运算在传回脚本
#这里的例子书中有个小错误,应如下写法
[root@tzPC 17Unit]# cat test12.sh #!/bin/bash #returning an array value function arraydblr { local origarray local newarray local elements local i origarray=($(echo "$@")) newarray=($(echo "$@")) elements=$[ $# - 1 ] for (( i=0;i<=$elements;i++ )) do newarray[$i]=$[ ${origarray[$i]}*2 ] done echo ${newarray[*]} } myarray=(1 2 3 4 5) echo "The original array is: ${myarray[*]}" arg1=$(echo ${myarray[*]}) #此时arg1的值为1 2 3 4 5 result=($(arraydblr $arg1)) echo "The new array is: ${result[*]}"
#执行结果 [root@tzPC 17Unit]# bash test12.sh The original array is: 1 2 3 4 5 The new array is: 2 4 6 8 10
函数递归
函数可以自己调用自己
例:计算阶乘,一个数的阶乘是该数之前所有数乘以该数的值,比如计算5的阶乘,如下
5!=1*2*3*4*5
=120
公式为x!=x*(x-1)
好吧,我卡在这个例子了,没弄懂
[root@tzPC 17Unit]# cat test13.sh #!/bin/bash #using recursion function factorial { if [ $1 -eq 1 ] then echo 1 #1的阶乘为1 else local temp=$[ $1 -1 ] local result=$(factorial $temp) echo $[ $result*$1 ] fi } read -p "Enter value: " value result=$(factorial $value) echo "The factorial of $value is: $result" [root@tzPC 17Unit]# bash test13.sh Enter value: 5 The factorial of 5 is: 120
创建库
方便在多个脚本中使用同一段代码,这段代码就叫做函数库文件,相当于类。
创建名为myfuncs的函数库
[root@tzPC 17Unit]# cat myfuncs #my script functions function addem { echo $[ $1 + $2 ] } function multem { echo $[ $1 * $2 ] } function divem { if [ $2 -ne 0 ] then echo $[ $1 / $2 ] else echo -1 fi }
将函数库文件添加到脚本中
这里要用到.跟source命令,因为运行脚本会在当前Shell中创建子Shell运行脚本,使用这两个命令会使脚本在当前shell中运行。
[root@tzPC 17Unit]# cat test14.sh #!/bin/bash #using functions defined in a library file . ./myfuncs value1=10 value2=5 result1=$(addem $value1 $value2) result2=$(multem $value1 $value2) result3=$(divem $value1 $value2) echo "The result of adding them is: $result1" echo "The result of multiplying them is: $result2" echo "The result of dividing them is: $result3" [root@tzPC 17Unit]# bash test14.sh The result of adding them is: 15 The result of multiplying them is: 50 The result of dividing them is: 2
在命令行中使用函数
在命令行上创建函数,缺点是退出shell时,函数就消失了
单行定义函数
[root@tzPC 17Unit]# function divem { echo $[ $1 /$2 ]; } [root@tzPC 17Unit]# divem 100 5 20
多条命令必须在后面加个分号分隔
[root@tzPC 17Unit]# function doubleit { read -p "Enter value: " value; echo $[ $value *2 ]; } [root@tzPC 17Unit]# doubleit Enter value: 20 40
多行方式定义函数
[root@tzPC 17Unit]# function multem { > echo $[ $1 * $2 ] > } [root@tzPC 17Unit]# multem 2 5 10
在.bashrc文件中定义函数
每次bash shell启动时自动加载~/.bashrc文件,可以在在此定义函数,或调用指定函数库文件路径。
[root@tzPC ~]# cat ~/.bashrc # .bashrc # User specific aliases and functions alias rm='rm -i' alias cp='cp -i' alias mv='mv -i' # Source global definitions if [ -f /etc/bashrc ]; then . /etc/bashrc fi echo "123" . /root/script/17Unit/myfuncs
下次bash shell启动时,就能在命令行界面使用定义的函数了
[root@tzPC ~]# addem 10 5 15 [root@tzPC ~]# multem 10 5 50 [root@tzPC ~]# divem 10 5 2
同样子shell也能调用此函数库文件
使用GNU shtool shell库
不止自己定义函数使用,还可以下载网上别人定义的函数用于自己的脚本中。
shtool库提供了一些简单的shell脚本函数,可用来完成日常的shell功能,如处理临时文件、目录或格式化输出
同样也可以在网上下载别人写的脚本,根据需求改一下自己使用
下载安装
浏览器中输入
ftp://ftp.gnu.org/gnu/shtool/
我这里下载的是书中案例2.0.8版本
在浏览器中输入
ftp://ftp.gnu.org/gnu/shtool/shtool-2.0.0.tar.gz
下载完成后使用rz命令上传到服务器中
使用tar命令提取文件
[root@tzPC 17Unit]# tar -zxvf shtool-2.0.0.tar.gz
构建库
configure命令会检查构建shtool库文件所需要的工具,并将其路径修改到shtool配置文件中。
[root@tzPC shtool-2.0.0]# ./configure Configuring GNU shtool (Portable Shell Tool), version 2.0.0 (02-Jul-2004) Copyright (c) 1994-2004 Ralf S. Engelschall <rse@engelschall.com> checking whether make sets $(MAKE)... yes checking for perl interpreter... /usr/bin/perl checking for pod2man conversion tool... /usr/bin/pod2man configure: creating ./config.status config.status: creating Makefile config.status: creating shtoolize config.status: executing adjustment commands
make命令用于构建shtool库文件
使用make测试库文件中的函数是否正常运行
[root@tzPC shtool-2.0.0]# make test Running test suite: echo...........ok mdate..........ok table..........ok prop...........ok move...........ok install........ok mkdir..........ok mkln...........ok mkshadow.......ok fixperm........ok rotate.........ok tarball........ok subst..........ok platform.......ok arx............ok slo............ok scpp...........ok version........ok path...........ok OK: passed: 19/19
以root运行make install选项安装shtool库
[root@tzPC shtool-2.0.0]# make install 1>/dev/null&& echo ok ok
安装完成就能在Shell脚本中使用这些函数了
shtool库函数
各函数介绍,书P376
shtool函数包含选项和参数,用于更改函数工作方式。
语法格式
shtool [options] [function [options] [args]]
使用库
在命令行中使用
[root@tzPC shtool-2.0.0]# shtool platform centos 7.4.1708 (AMD64)
在脚本中使用
[root@tzPC shtool-2.0.0]# cat test16.sh #!/bin/bash shtool platform [root@tzPC shtool-2.0.0]# bash test16.sh centos 7.4.1708 (AMD64)
prop函数可以创建一个旋转进度条,可以玩玩
[root@tzPC 17Unit]# bash test15.sh | shtool prop -p "waiting..." waiting....\
学习来自:《Linux命令行与Shell脚本大全 第3版》第17章