9.shell 函数

函数

在Shell中,函数是一段可重复使用的代码块,用于封装重复使用的代码,以提高代码的简洁性和可读性。

Shell函数的定义有两种格式:

使用function关键字定义函数:

格式:

function 函数名 { 
	命令序列 
}

function 函数名 { 
	命令序列; 
	return 返回值; 
}

不使用function关键字定义函数:

格式:

函数名 () { 
	命令序列
}

函数名 () { 
	命令序列;
	 return 返回值; 
}

函数的返回值

函数的返回值可以通过return命令显式返回,或者使用echo等命令输出。
return表示退出函数并返回一个退出值,脚本中可以用$?变量显示该值
退出状态码必须是0~255,超出时值将为除以256取余

函数的退出状态码通常用于脚本中判断函数的执行结果。

函数的变量作用范围通常只在脚本内的shell环境中有效

案例1:

#!/bin/bash

function test01 {

read -p "请输入一个整数:" num

return $[num * 2]

}

test01

echo $? # 输出函数test01的返回值

在这个例子中,test01函数通过read命令读取用户输入的整数,并使用return命令返回该整数的两倍。调用该函数后,使用echo $?输出函数的返回值。

脚本执行效果:

这里因为超出255时值将为除以256取余
400*2=800
800对256求余得32

在这里插入图片描述
在这里插入图片描述

案例2:
is_server_running(){
    systemctl status $1 &>/dev/null
        if [ $? -eq 0 ];then
            return 0
        else
            return 1
        fi
}
#调用函数,并根据函数返回状态码进行输出
is_server_running $1 && echo "$1 is Running" || echo "$1 is stoped"

在这里插入图片描述


函数local 变量

在函数体内执行local 变量,可将变量限定在函数体内部使用,
即local定义的变量值只能在函数体内部使用,出了函数体将无法使用;

案例1:

函数内变量加了local的效果

#!/bin/bash

name () {
  echo $name
  local name=wang
  echo $name

}
name=liu
name
echo $name

加了local的变量只能在函数内使用
在这里插入图片描述

函数内变量没加local的效果

#!/bin/bash

name () {
  echo $name
  name=wang
  echo $name

}
name=liu
name
echo $name

没加local的变量在函数外也能使用
在这里插入图片描述


函数传参

在Shell脚本中,可以通过在函数定义时指定参数来传递参数,
并在函数内部通过$1, $2, 来分别访问这些参数。

案例1:
#!/bin/bash

function print () {
  echo "参数1: $1"
  echo "参数2: $2"
}

# 调用函数并传递两个参数
print "Hello" "World"

脚本执行效果:
在这里插入图片描述

案例2:
#!/bin/bash
fun () {
    echo "Hello $1"
        #$1 函数的参数
}

#调用函数,后面跟上参数,这种叫函数传参。
fun $1
#$1 脚本的位置参数,需要在执行脚本时传递。

#注意:
    #脚本传递参数,是不会传递给函数的。如何才能做到脚本传参,能够传递到函数中去呢?
    #我们可以将脚本的位置参数,作为函数的参数,这样就可以实现联动了。

执行脚本时传递参数
在这里插入图片描述


函数库文件

可以将经常使用的函数存入一个单独的文件,
然后将文件载入shell,再进行调用函数。

实现过程:
创建函数文件,只存放函数的定义
在脚本或交互式shell中调用函数库文件

. ./filename
或
source filename
案例1:

函数库文件

vim fun.sh

#!/bin/bash


print1 () {
  echo "$1 $2"
}

print2 () {
  echo "$1 $2 $3"
}

在脚本中调用函数库文件

#!/bin/bash

. ./fun.sh #调用函数库文件

print1 "你" "好" #调用函数并传参

print2 "你" "也" "好"

脚本执行效果:

在这里插入图片描述


实践

案例1:

写一个脚本,实现nginx服务的启动、停止、重启。

#!/bin/bash

ngx_sta () {
	if [ $? -eq 0 ];then
		echo "nginx is $1 success"
	else
		echo "nginx is $1 error"

	fi
}

case $1 in
	start)
		systemctl $1 nginx  #脚本的位置参数作为函数的参数。
		ngx_sta $1
		;;
	stop)
		systemctl $1 nginx
		ngx_sta $1
		;;
	reload)
		systemctl $1 nginx
		ngx_sta $1
		;;
	restart)
		systemctl $1 nginx
		ngx_sta $1
		;;
	*)
		echo "usage: $0 [ start | stop | reload | restart ]"
		;;
esac

脚本执行效果:

在这里插入图片描述


案例2:

1.写一个类似跳板机的功能

思路梳理:
第一步、免密
前提是连到每台机器之前需要先完成对每台机器的免密工作
先在本地生成密钥对
ssh-keygen

再将生成的公钥发给被登录的机器
ssh-copy-id -i ~/.ssh/id_rsa.pub root@192.168.xx.xxx

按照提示输入被登录的机器的密码即可

第二步、准备脚本
这里用到了一个命令trap
trap命令用于指定在接收到信号后将要采取的动作
trap接收信号之后,可以有三种反应方式:
1,执行一段程序来处理这一信号
2, 接受信号的默认操作
3, 忽视这一信号

第一种形式的trap命令在shell接收到信号时,将执行双引号中的命令。 
trap "命令" 信号名或信号编号
 
为了恢复信号的默认操作,使用第二种形式的trap命令:
trap 信号名或信号编号
 
第三种形式的trap命令允许忽视信号
trap "" 信号名或信号编号

运行格式:trap command signal
command部分是接收到指定信号时将要采取的行动,
signal部分是要处理的信号名。

以下是一些信号(括号里面的数字是信号的编号)

信号          说明 

HUP(1)      挂起,通常因终端掉线或用户退出而引发 
INT(2)      中断,通常因按下Crtl+C组合健而引发                 
QUIT(3)     退出,通常因某些严重的执行错误而引发         
ABRT(6)     中止,通常因某些严重的执行错误而引发         
ALRM(14)    报警,通常用来处理超时 
TERM(15)    终止,通常在系统关机时发送 
TSTP(20)    停止进程的运行

例:
trap "" 2 :屏蔽INT信号,按Crtl+C健,终端无反应
在这里插入图片描述

trap "" HUP INT TSTP
屏蔽忽视HUP、INT、TSTP信号,挂起、中断、停止进程的运行等操作,程序是不会退出的

在这里插入图片描述

脚本内容:

#!/bin/bash

access () {  #定义一个函数,输出菜单
cat <<EOF
-------欢迎访问Jumpserver--------------
1) web1-192.168.xx.164
2) web1-192.168.xx.165
3) web1-192.168.xx.167
h) menu
q) exit
---------------------------------------
EOF
}

access #脚本一执行就调用函数

trap "" HUP INT TSTP #屏蔽这些信号,接收到这些信号后终端不会有任何反应

while true #死循环
do
    read -p "选择你的操作: [ 1 | 2 | 3 | h | q ] " Action

    case $Action in
        1)
            ssh root@192.168.xx.164 #当输入1 时就会登录192.168.xx.164这台机器
            ;;
        2)
            ssh root@192.168.xx.165 #当输入2 时就会登录192.168.xx.165这台机器
            ;;
        3)
            ssh root@192.168.xx.167 #当输入3 时就会登录192.168.xx.167这台机器
            ;;
        h)
            clear #当输入h就会清理屏幕,再次调用函数输出菜单
            access
            ;;
        q)
            exit #当输入q 就会退出脚本
            ;;
        *)
            continue #输入其他任何,就会结束本次循环,重新提示用户输入,继续下一次的循环
    esac
done

脚本执行效果:

主菜单样式:
在这里插入图片描述

当输入1 时就会登录192.168.xx.164这台机器
在这里插入图片描述

当输入2 时就会登录192.168.xx.165这台机器
在这里插入图片描述

当输入3 时就会登录192.168.xx.167这台机器
在这里插入图片描述

当输入q 就会退出脚本
在这里插入图片描述

输入其他任何,就会结束本次循环,继续下一次的循环,重新提示用户输入
在这里插入图片描述


2.实现一个多级菜单
一级菜单可以退出脚本
二级菜单可以退回到一级菜单

具体如下
在这里插入图片描述

脚本:

#!/bin/bash

menu_1 () {
cat <<EOF
------------------一级菜单--------------
1) Install Nginx Server
2) Install PHP Server
3) Install Redis Server
4) Quit
----------------------------------------
EOF
}

menu2_nginx () {
cat <<EOF
------------------二级页面--------------
1) Install Nginx 1.23.0
2) Install Nginx 1.24.0
3) Install Nginx 1.25.4
4) 返回上一级菜单
5) Quit
----------------------------------------
EOF
}

menu2_php () {
cat <<EOF
------------------二级页面--------------
1) Install php 8.3.0
2) Install php 8.2.0
3) Install php 7.4.33
4) 返回上一级菜单
5) Quit
----------------------------------------
EOF
}

menu2_redis () {
cat <<EOF
------------------二级页面--------------
1) Install redis 6.0.0
2) Install redis 7.0.0
3) Install redis 7.2.4
4) 返回上一级菜单
5) Quit
----------------------------------------
EOF
}

menu_1 #执行脚本后调用展示一级页面的函数

while true #死循环
do
	read -p "输入你需要安装的服务编号: [ 1 | 2 | 3 | 4 ] " action
	case $action in
	
		1) #当用户输入1时,展示二级nginx安装页面
			clear
			menu2_nginx #调用函数,展示二级nginx安装页面
			while true
				do
					read -p "输入你需要安装的服务编号: [ 1 | 2 | 3 | 4 | 5 ] " action_nginx
					case $action_nginx in
						1)
							echo "install nginx 1.23.0 is done"
							;;
						2)
                            echo "install nginx 1.24.0 is done"
                            ;;
						3)
                            echo "install nginx 1.25.4 is done"
                            ;;
						4) #返回一级页面 
							clear
							menu_1 #调用函数,展示一级页面
                            break  #退出当前循环
                            ;;
						5)
							exit #退出脚本
							echo "bye ~"
							;;
						*)
							continue #结束本次循环,继续执行下一次循环
							;;
					esac
				done
			;;
		2)
			clear
                        menu2_php
                        while true
                                do
                                        read -p "输入你需要安装的服务编号: [ 1 | 2 | 3 | 4 | 5 ] " action_php
                                        case $action_php in
                                                1)
                                                        echo "install php 8.3.0 is done"
                                                        ;;
                                                2)
                                                        echo "install php 8.2.0 is done"
                                                        ;;
                                                3)
                                                        echo "install php 7.4.33 is done"
                                                        ;;
                                                4)
                                                        clear
                                                        menu_1
                                                        break
                                                        ;;
						  						5)
                                                        exit
                                                        echo "bye ~"
                                                        ;;
                                                *)
                                                        continue
                                                        ;;
                                        esac
                                done
                        ;;
		3)
			clear
                        menu2_redis
                        while true
                                do
                                        read -p "输入你需要安装的服务编号: [ 1 | 2 | 3 | 4 | 5 ] " action_redis
                                        case $action_redis in
                                                1)
                                                        echo "install redis 6.0.0 is done"
                                                        ;;
                                                2)
                                                        echo "install redis 7.0.0 is done"
                                                        ;;
                                                3)
                                                        echo "install redis 7.2.4 is done"
                                                        ;;
                                                4)
                                                        clear
                                                        menu_1
                                                        break
                                                        ;;
												5)
                                                        exit
                                                        echo "bye ~"
                                                        ;;
                                                *)
                                                        continue
                                                        ;;
                                        esac
                                done
                        ;;
		4)
			exit
			echo "bye ~"
			;;
		*)
			continue
			;;
	esac
done

脚本执行结果

执行脚本展示,一级菜单页面
在这里插入图片描述

按下1进入第一个二级页面
按下数字执行对应安装操作
按下4会清空屏幕,展示一级页面,这里为了展示,又将终端历史输出调了出来
按下5会退出脚本
在这里插入图片描述

在这里插入图片描述

后面的php和redis操作一样,就不展示了

  • 22
    点赞
  • 25
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值