Shell编程——函数

函数

1、Shell函数的概念与作用介绍

在讲解Shell函数之前,先来回顾Linux系统中别名的作用。

bash 复制代码
[root@oldboy ~]# alias ssh='/etc/init.d/sshd'
[root@oldboy ~]# ssh restart #<==执行ssh就相当于执行了/etc/init.d/sshd,最直
                                      接的好处就是简化了输入。
停止 sshd:                                                        [确定]
正在启动 sshd:                                                    [确定]

函数也有类似于别名的作用,例如可简化程序的代码量,让程序更易读、易改、易用。

简单地说,函数的作用就是将程序里多次被调用的相同代码组合起来(函数体)​,并为其取一个名字(即函数名)​,其他所有想重复调用这部分代码的地方都只需要调用这个名字就可以了。当需要修改这部分重复代码时,只需要改变函数体内的一份代码即可实现对所有调用的修改,也可以把函数独立地写到文件里,当需要调用函数时,再加载进来使用。

使用Shell函数的优势整理如下:

  • 把相同的程序段定义成函数,可以减少整个程序的代码量,提升开发效率。
  • 增加程序的可读性、易读性,提升管理效率。
  • 可以实现程序功能模块化,使得程序具备通用性(可移植性)。

对于Shell来说,Linux系统里的近2000个命令可以说都是Shell的函数,所以, Shell的函数也是很多的,这一点需要读者注意。

2、Shell函数的语法

下面是Shell函数的常见语法格式。

其标准写法为:

bash 复制代码
function 函数名() {        #<==作者推荐的书写函数的方法(带括号)
    指令...
    return n
}

简化写法1:

bash 复制代码
function 函数名{           #<==不推荐读者使用此方法(无括号)
    指令...
    return n
}

在Shell函数的语法中,当有function时,函数名后面的小括号"​(​)​"部分可以省略不写。

简化写法2:

bash 复制代码
函数名() {                   #<==不用function的方法
    指令...
    return n
}

在Shell函数的语法中,function表示声明一个函数,这部分可以省略不写。

3、Shell函数的执行

Shell的函数分为最基本的函数和可以传参的函数两种,其执行方式分别说明如下。

  • 1)执行不带参数的函数时,直接输入函数名即可(注意不带小括号)​。格式如下:

    bash 复制代码
    函数名

    有关执行函数的重要说明:

    • 执行Shell函数时,函数名前的function和函数后的小括号都不要带。
    • 函数的定义必须在要执行的程序前面定义或加载。
    • Shell执行系统中各种程序的执行顺序为:系统别名→函数→系统命令→可执行文件。
    • 函数执行时,会和调用它的脚本共用变量,也可以为函数设定局部变量及特殊位置参数。
    • 在Shell函数里面,return命令的功能与exit类似,return的作用是退出函数,而exit是退出脚本文件。
    • return语句会返回一个退出值(即返回值)给调用函数的当前程序,而exit会返回一个退出值(即返回值)给执行程序的当前Shell。
    • 如果将函数存放在独立的文件中,被脚本加载使用时,需要使用source或". "来加载。
    • 在函数内一般使用local定义局部变量,这些变量离开函数后就会消失。
  • 2)带参数的函数执行方法,格式如下:

    bash 复制代码
    函数名 参数1 参数2

    函数后接参数的说明:

    • Shell的位置参数(1、 2 ... 、 2...、 2...、#、 ∗ 、 \*、 ∗、?及@)都可以作为函数的参数来使用。
    • 此时父脚本的参数临时地被函数参数所掩盖或隐藏。
    • 当函数执行完成时,原来的命令行脚本的参数即可恢复。
    • 函数的参数变量是在函数体里面定义的。

4、Shell函数的基础实践

范例:开发脚本建立两个简单函数并调用执行。

bash 复制代码
[root@oldboy scripts]# cat 8_1.sh
#! /bin/bash
#定义两个函数,名字为oldboy和oldgirl。
oldboy(){
    echo "I am oldboy."
}
function oldgirl(){
    echo "I am oldgirl."
}
oldboy              #<==在一个脚本里执行函数名调用函数。
oldgirl             #<==在一个脚本里执行函数名调用函数。

务必要先定义函数然后再执行函数,否则会报错,示例如下:

bash 复制代码
[root@oldboy scripts]# cat 8_2.sh
#! /bin/bash
oldgirl
function oldgirl(){
   echo "I am oldgirl."
}
oldgirl
[root@oldboy scripts]# sh 8_2.sh
8_2.sh: line 2: oldgirl: command not found     #<==提示:第二行因为oldgirl函数不存在,所以就把oldgirl当作命令了,但是系统又没有oldgirl命令。
I am oldgirl.

范例:分离函数体和执行函数的脚本文件(更规范的方法)​。

首先建立函数库脚本(默认不会执行函数)​。

使用cat命令追加多行文本,以将函数代码追加到系统的函数文件中,即/etc/init.d/functions,命令如下:

bash 复制代码
cat >>/etc/init.d/functions<<- EOF         #<==here文档的另一种写法,此写法允许后面的EOF可以使用Tab键,而不顶格。
oldboy(){
    echo "I am oldboy."
}
EOF                                            #<==就是这里的EOF可以使用Tab键,而不顶格,但不能使用空格。

追加的函数代码如下:

bash 复制代码
[root@oldboy scripts]# tail -3 /etc/init.d/functions
oldboy(){
    echo "I am oldboy."
}

然后开发执行脚本以调用上述函数。

bash 复制代码
[root@oldboy scripts]# cat 8_3.sh
#! /bin/bash
#加载函数所在的文件(functions是Linux系统内置的脚本函数库)
[ -f /etc/init.d/functions ] && . /etc/init.d/functions || exit 1
#提示:可以用source 或"."(点号)来加载脚本functions中的命令或变量参数等。
#调用函数
oldboy

执行结果如下:

bash 复制代码
[root@oldboy scripts]# sh 8_3.sh
I am oldboy.

范例:写出带参数的Shell函数示例。

这里通过建立函数oldgirl来做示例讲解,代码截图如图所示。

范例:将函数的传参转换成脚本文件命令行传参。

参考答案见图。

5、利用Shell函数开发企业级URL检测脚本

范例:将函数的传参转换成脚本文件命令行传参,判断任意指定的URL是否存在异常。

程序设计思路及实现:

  • 1)实现脚本传参,检查Web URL是否正常。

    bash 复制代码
    [root@oldboy scripts]# cat 8_5.sh
    #! /bin/sh
    #判断传参个数是否为1个。
    if [ $# -ne 1 ]
      then
        echo $"usage:$0 url"
        exit 1
    fi
    #利用wget进行访问测试,wget的相关参数在前面章节已经讲解过了。
    wget --spider -q -o /dev/null --tries=1 -T 5 $1  #<==-T指定超时时间,这里的$1为脚本的参数。
    if [ $? -eq 0 ]
      then
        echo "$1 is yes."
    else
        echo "$1 is no."
    fi
  • 2)将上述检测的功能写成函数,并将函数传参转换成脚本命令行传参,判断任意指定的URL是否存在异常。

    bash 复制代码
    [root@oldboy scripts]# cat 8_5_1.sh
    #! /bin/sh
    function usage(){      #<==帮助函数。
        echo $"usage:$0 url"
        exit 1
    }
    function check_url(){ #<==检测URL函数。
        wget --spider -q -o /dev/null --tries=1 -T 5 $1  #<==这里的$1就是函数传参。
        if [ $? -eq 0 ]
          then
            echo "$1 is yes."
        else
            echo "$1 is no."
        fi
    }
    function main(){             #<==主函数。
        if [ $# -ne 1 ]          #<==如果传入的是多个参数,则打印帮助函数,提示用户。
          then
            usage
        fi
        check_url $1             #<==接收函数的传参,即把下文main结尾的$*传到这里。
    }
    main $*                     #<==这里的$*就是把命令行接收的所有参数作为函数参数传给函数内部,是一种常用手法。

    执行结果如下:

    bash 复制代码
    [root@oldboy scripts]# sh 8_5_1.sh
    usage:8_5_1.sh url
    [root@oldboy scripts]# sh 8_5_1.sh   www.oldboyedu.com
    www.oldboyedu.com is yes.
    [root@oldboy scripts]# sh 8_5_1.sh   www.oldgirl123.com
    www.oldgirl123.com is no.

范例:将函数的传参转换成脚本文件命令行传参,判断任意指定的URL是否存在异常,并以更专业的输出显示,效果如图所示。

参考答案:

bash 复制代码
[root@oldboy scripts]# cat 8_6.sh
#! /bin/sh
. /etc/init.d/functions  #<==引入系统函数库。
function usage(){
    echo $"usage:$0 url"
    exit 1
}
function check_url(){
    wget --spider -q -o /dev/null --tries=1 -T 5 $1
    if [ $? -eq 0 ]
      then
        action "$1 is yes." /bin/true      #<==这里的action就是在脚本开头引入系统函数库后调用的。
    else
        action "$1 is no." /bin/false
    fi
}
function main(){
    if [ $# -ne 1 ]
      then
        usage
    fi
    check_url $1
}
main $*

执行效果如下:

bash 复制代码
[root@oldboy scripts]# sh 8_6.sh www.oldboedu.com  #<==输入错误地址。
www.oldboedu.com is no.                                           [失败]
[root@oldboy scripts]# sh 8_6.sh www.oldboyedu.com
www.oldboyedu.com is yes.                                         [确定]
相关推荐
PC2005-cloud1 小时前
Qdrant 连接失败排查:localhost 解析到 __1,而 Docker 只绑了 IPv4
运维·docker·容器
电子制造自留地2 小时前
AI服务器PCB的超低损耗材料选型逻辑
运维·服务器·人工智能·科技·制造·科普·pcb工艺
码少女2 小时前
Linux——多路复用之poll模型
linux·服务器·网络
蓝速科技2 小时前
会议室门牌触控预约选型与落地实战指南丨蓝速科技
大数据·运维·数据库·人工智能·科技
PatrickYao04222 小时前
Linux安装UV
linux·运维·uv
蓝速科技2 小时前
企业展厅数字人导览效果提升与选型实战指南丨蓝速科技
大数据·运维·数据库·人工智能·科技·microsoft
顶点多余2 小时前
面试题总结 ---Linux篇
linux·运维·服务器
normanhere3 小时前
防火墙来回路径不一致导致的网速异常
运维·服务器·网络
T1mzhou3 小时前
ARM64 Linux 6.10 内核驱动(14):drivers/base/platform.c:板级设备主战场
linux·c语言·开发语言·arm开发