当前位置: 首页 > news >正文

【网络运维】Shell脚本编程:函数

Shell脚本编程:函数

Shell 函数介绍

在 Shell 编程中,函数是一种非常重要的代码组织和复用机制。我们可以将函数理解为一种“高级别名”,它不仅能够简化代码,还能提高程序的可读性和可维护性。

alias 类似,函数可以封装常用操作:

# 使用 alias 简化命令
alias ll='ls -l --color=auto'
ll /home/

但函数比 alias 更强大,它能够:

  • 减少代码重复,提升开发效率
  • 增强程序可读性和可管理性
  • 实现程序功能模块化,提高可移植性

Shell 函数的语法

Shell 函数有三种常见的定义方式:

标准写法

function 函数名 () {指令...return n
}

简化写法1:省略小括号

function 函数名 {指令...return n
}

简化写法2:省略 function 关键字

函数名 () {指令...return n
}

Shell 函数的执行

1. 执行不带参数的函数

直接输入函数名即可(不需要小括号):

函数名

重要说明:

  • 函数定义必须在调用之前
  • Shell 执行优先级:系统别名 → 函数 → 系统命令 → 可执行文件
  • 函数内使用 return 退出函数,exit 退出整个脚本
  • 使用 local 定义局部变量,这些变量在函数外不可见
  • 独立函数文件需要使用 source. 加载

2. 执行带参数的函数

函数名 参数1 参数2

参数说明:

  • 使用 $1, $2$n 获取参数
  • $# 表示参数个数,$*$@ 表示所有参数
  • $0 仍然是父脚本的名称
  • 函数参数会临时覆盖父脚本的参数

Shell 函数实践示例

示例1:基础 hello 函数

#!/bin/bash
# 定义函数
function hello () {echo "Hello World !"
}
# 调用函数
hello

执行结果:

Hello World !

错误示例:先调用后定义

#!/bin/bash
hello  # 此时函数还未定义,会报错
function hello () {echo "Hello World !"
}

执行结果:

fun2.sh: line 2: hello: command not found

关键点:函数必须先定义后调用

示例2:调用外部函数文件

创建函数库文件:

# 创建名为 mylib 的函数库
cat >> mylib << 'EOF'
function hello () {echo "Hello World !"
}
EOF

在主脚本中调用:

#!/bin/bash
# 检查函数库是否存在并可读
if [ -r mylib ]; thensource mylib  # 加载函数库
elseecho "mylib does not exist or is not readable"exit 1
fihello  # 调用函数

执行结果:

Hello World !

关键点:使用 source. 命令加载外部函数定义

示例3:带参数的函数

#!/bin/bash
function print () {# 根据参数值输出不同颜色的文本if [ "$1" == "PASS" ]; thenecho -e '\033[1;32mPASS\033[0;39m'  # 绿色elif [ "$1" == "FAIL" ]; thenecho -e '\033[1;31mFAIL\033[0;39m'  # 红色elif [ "$1" == "DONE" ]; thenecho -e '\033[1;35mDONE\033[0;39m'  # 紫色elseecho "Usage: print PASS|FAIL|DONE"fi
}# 获取用户输入
read -p "请输入你想要打印的内容:" str
print $str  # 调用函数并传递参数

测试结果:

# 运行脚本
请输入你想要打印的内容:PASS
PASS(绿色显示)请输入你想要打印的内容:hello
Usage: print PASS|FAIL|DONE

关键点:函数内部通过 $1 获取第一个参数

示例4:函数参数与脚本参数

#!/bin/bash
function print () {if [ "$1" == "PASS" ]; thenecho -e '\033[1;32mPASS\033[0;39m'elif [ "$1" == "FAIL" ]; thenecho -e '\033[1;31mFAIL\033[0;39m'elif [ "$1" == "DONE" ]; thenecho -e '\033[1;35mDONE\033[0;39m'else# 注意:这里的 $0 仍然是脚本名,不是函数名echo "Usage: $0 PASS|FAIL|DONE"fi
}str=$2  # 获取脚本的第二个参数
print $str  # 传递给函数

测试结果:

bash fun5.sh PASS FAIL
FAIL  # 显示的是第二个参数FAIL,而不是第一个参数PASSbash fun5.sh
Usage: fun5.sh PASS|FAIL|DONE  # $0 显示脚本名

关键点:函数参数会覆盖脚本参数,但 $0 始终指向脚本名称

函数实战:URL检测脚本

#!/bin/bash
# 使用方法提示函数
function usage () {echo "usage: $0 url"exit 1
}# URL检测函数
function check_url () {# 使用wget检测URL可访问性wget --spider -q -o /dev/null --tries=1 -T 5 $1# 根据返回状态码判断结果[ $? -eq 0 ] && echo "$1 is accessible" || echo "$1 is not accessible"
}# 主函数
function main () {# 检查参数个数是否正确[ $# -ne 1 ] && usagecheck_url $1
}# 执行主函数,传递所有参数
main $*

测试结果:

bash check_url.sh www.baidu.com
www.baidu.com is accessiblebash check_url.sh www.nonexistent.com
www.nonexistent.com is not accessible

关键点:模块化设计,分离功能逻辑,提高代码可维护性

函数的递归调用

示例1:计算1到n的累加和

#!/bin/bash
function sum_out() {if [ $1 -eq 1 ]; thensum=1  # 递归基线条件else# 递归调用:n + (n-1)的和sum=$[ $1 + $(sum_out $[ $1 - 1 ]) ]fiecho $sum
}read -p "输入一个你想计算和的整数:" num
sum_out $num

示例2:计算n的阶乘

#!/bin/bash
function fact_out() {if [ $1 -eq 1 ]; thensum=1  # 递归基线条件else# 递归调用:n * (n-1)的阶乘sum=$[ $1 * $(fact_out $[ $1 - 1 ]) ]fiecho $sum
}read -p "输入一个你想计算阶乘的整数:" num
fact_out $num

示例3:fork炸弹(⚠️危险示例,请勿实际运行)

:(){ :|:& };:

代码解析:

  • :() - 定义函数名为冒号
  • { :|:& } - 函数体:递归调用自身两次,并通过管道并行执行
  • ; - 命令分隔符
  • : - 调用函数,启动炸弹

原理:无限递归创建进程,耗尽系统资源

防范措施:限制用户进程数

ulimit -u 100  # 限制用户最多100个进程
http://www.xdnf.cn/news/1360441.html

相关文章:

  • 深度学习之第二课PyTorch与CUDA的安装
  • AOSP构建指南:从零开始的Android源码之旅
  • Docker 容器(一)
  • 【Docker基础】Docker-compose常用命令实践(三):镜像与配置管理
  • 【零代码】OpenCV C# 快速开发框架演示
  • 电路学习(四)二极管
  • 【计算机视觉】CaFormer
  • Java:LinkedList的使用
  • 【Protues仿真】基于AT89C52单片机的温湿度测量
  • 【文献阅读】生态恢复项目对生态系统稳定性的影响
  • 在JavaScript中,比较两个数组是否有相同元素(交集)的常用方法
  • 解决编译osgEarth中winsocket2.h找不到头文件问题
  • Node.js自研ORM框架深度解析与实践
  • C++11新特性全面解析(万字详解)
  • Starlink第三代终端和第二代终端的差异性有哪些?
  • Flink SQL执行SQL错误排查
  • MySQL的安装和卸载指南(入门到入土)
  • ZKmall模块商城的推荐数据体系:从多维度采集到高效存储的实践
  • 从“小麻烦”到“大难题”:Spring Boot 配置文件的坑与解
  • 04-ArkTS编程语言入门
  • 使用UE5开发《红色警戒3》类战略养成游戏的硬件配置指南
  • 源码导航页
  • Linux网络启程
  • 毛选一卷解析
  • 时间复杂度
  • C++STL底层原理:探秘标准模板库的内部机制
  • 大数据毕业设计选题推荐:基于Spark+Django的学生创业数据分析可视化系统详解 毕业设计/选题推荐/深度学习/数据分析/数据挖掘/机器学习/随机森林
  • Go语言IDE安装与配置(VSCode)
  • wpf之DockPanel
  • Python 闭包详解