十二、函数

函数的定义

将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

需要注意两点:

  1. 函数一结束就要取返回值,以免被其他命令执行结果覆盖了当前函数的返回值
  2. 退出状态码取值范围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章

 

posted @ 2020-08-21 22:46  努力吧阿团  阅读(188)  评论(0编辑  收藏  举报