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

Shell脚本高级技巧与错误处理

超越基础:Shell脚本高级技巧与错误处理

掌握了Shell脚本的基础后,是时候迈向更高层次——编写健壮、高效且可维护的脚本。

函数与模块化:如何编写可复用的函数

当脚本变得复杂时,重复代码会降低可读性和维护性。函数可以将代码模块化,提高复用性。

定义和调用函数

函数定义无需特别关键字,直接写函数名和代码块:

#!/bin/bash 
# 定义函数 
say_hello() {
	echo "Hello, $1!" 
} 
# 调用函数 
say_hello "Alice"
say_hello "Bob"

输出:

Hello, Alice! 
Hello, Bob!

在这里插入图片描述

  • $1 是函数的第一个参数,类似脚本中的命令行参数。

带返回值的函数

Shell函数返回值通常通过全局变量或退出码实现:

#!/bin/bash 
add_numbers() {
	local SUM=$(( $1 + $2 ))
    echo $SUM  # 输出结果 
}
RESULT=$(add_numbers 3 5) 
echo "3 + 5 = $RESULT"

输出:3 + 5 = 8
在这里插入图片描述

模块化实践

将常用功能封装成函数,并保存到外部文件(如 utils.sh),然后在脚本中引入:

# utils.sh
log() {
	echo "$(date '+%Y-%m-%d %H:%M:%S') - $1" >> /var/log/script.log 
}
#!/bin/bash
source ./utils.sh
log "脚本开始执行"
echo "做一些工作..." 
log "脚本结束"

通过 source 或 .引入外部文件,实现代码复用。
在这里插入图片描述


错误处理:退出码、trap和日志

生产环境的脚本必须能处理错误,避免因异常导致系统混乱。

使用退出码

每个命令执行后都有一个退出码(0 表示成功,非 0 表示失败),可用 $? 检查:

#!/bin/bash 
ls /nonexistent 
if [ $? -ne 0 ]; then
	echo "错误:目录不存在"    
	exit 1  # 非零退出码表示脚本失败 
fi

在这里插入图片描述

trap捕获信号

trap 命令可捕获中断信号(如Ctrl+C)或脚本退出时的状态:

#!/bin/bash
cleanup() {
	echo "脚本被中断,正在清理..."
    # 清理临时文件等
    exit 1 
}
trap cleanup INT TERM  # 捕获中断和终止信号 
echo "运行中,按Ctrl+C测试" 
sleep 100

按Ctrl+C后,脚本会执行 cleanup 函数。
在这里插入图片描述

记录错误日志

将错误信息记录到日志文件,便于排查问题:

#!/bin/bash 
LOG_FILE="/var/log/script_errors.log" 
log_error() {
	echo "$(date) - ERROR: $1" >> "$LOG_FILE"
}
ls /nonexistent 2>/dev/null || log_error "无法访问目录"
echo "继续执行..."
  • 2>/dev/null:屏蔽标准错误输出。
  • ||:前命令失败时执行后命令。

脚本优化:提高性能的最佳实践

高效的脚本不仅功能强大,还要运行迅速且资源占用低。

1. 减少外部命令调用

频繁调用外部命令(如 grep、awk)会增加开销,尽量使用Shell内置功能:

# 低效 
COUNT=$(ls -l | wc -l) 
# 高效 
files=( * )
COUNT=${#files[@]}

2. 并行执行

对于耗时任务,使用后台进程(&)并行运行:

#!/bin/bash
task() {
	echo "任务 $1 開始"
    sleep 2
    echo "任務 $1 完成" 
}
task 1 &
task 2 &
wait  # 等待所有后台任务完成

3. 避免冗余操作

缓存重复使用的结果:

#!/bin/bash
# 每次调用date都重新计算
for i in {1..3}; do
	echo "$(date) - 循环 $i" 
done 
# 优化:只计算一次 
NOW=$(date)
for i in {1..3}; do
	echo "$NOW - 循环 $i"
done

实战案例:自动化用户管理

以下是一个完整的用户管理脚本,包含创建、删除用户和权限设置功能。

#!/bin/bash
LOG_FILE="/var/log/user_management.log"
USERNAME=""
ACTION=""
# 函数:记录日志
log() {
	echo "$(date '+%Y-%m-%d %H:%M:%S') - $1" >> "$LOG_FILE" 
}

# 函数:检查用户是否存在 
check_user() {
	if id "$1" &>/dev/null; then
    	return 0  # 用户存在    
    else
    	return 1    
    fi
}

# 函数:创建用户
create_user() {
	if check_user "$1"; then
    	log "用户 $1 已存在"        
    	echo "用户 $1 已存在"
    else
    	useradd -m "$1" && echo "用户 $1 创建成功" || log "创建用户 $1 失败"
        passwd "$1"  # 设置密码
        chmod 700 "/home/$1"  # 设置权限     
        log "用户 $1 创建并配置完成"
    fi
}

# 函数:删除用户
delete_user() {
	if check_user "$1"; then
    	userdel -r "$1" && echo "用户 $1 删除成功" || log "删除用户 $1 失败"
        log "用户 $1 已删除"
    else
    	echo "用户 $1 不存在"
        log "尝试删除不存在的用户 $1"
    fi
} 

# 主逻辑
if [ $# -ne 2 ]; then
	echo "用法:$0 {create|delete} 用户名"
	exit 1
fi 

ACTION=$1
USERNAME=$2

case $ACTION in
	create) create_user "$USERNAME";;
    delete) delete_user "$USERNAME";;
    *) echo "无效操作:$ACTION"; exit 1;;
esac
exit 0

使用方法

  • 创建用户:./user_manage.sh create testuser
  • 删除用户:./user_manage.sh delete testuser

功能亮点

  • 模块化:将创建和删除逻辑封装为函数。
  • 错误处理:检查用户是否存在,记录失败日志。
  • 安全性:设置合理的目录权限。

http://www.kler.cn/a/561853.html

相关文章:

  • WebUI 部署 Ollama 可视化对话界面
  • Directx上传堆和默认堆注意事项
  • WPS中Word表格做好了,忘记写标题了怎么办?
  • 深入理解 Flink 中的 .name() 和 .uid() 方法
  • 网络安全-系统层攻击流程及防御措施
  • web安全——web应用程序技术
  • 智能证件照处理器(深度学习)
  • PHP 连接 Memcached 服务
  • 腾讯云cos 临时密钥 适用于前端直传等临时授权场景
  • 在嵌入式Linux中实现高并发TCP服务器:从select到epoll的演进与实战
  • Spring Cloud源码 - Eureka源码原理分析
  • MFC学习笔记-1
  • 基本网络安全的实现
  • 火语言RPA--Excel设置列宽
  • 分治算法、动态规划、贪心算法、分支限界法和回溯算法的深度对比
  • 十类DeepSeek学术提示词分享
  • 心理咨询小程序的未来发展
  • deepseek部署:ELK + Filebeat + Zookeeper + Kafka
  • WEEX交易所安全教學:如何應對剪切板被劫持駭客攻擊?
  • leetcode226-翻转二叉树