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

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

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

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

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

定义和调用函数

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

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

输出:

text 复制代码
Hello, Alice! 
Hello, Bob!
  • $1 是函数的第一个参数,类似脚本中的命令行参数。

带返回值的函数

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

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

输出:3 + 5 = 8

模块化实践

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

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

通过 source 或 .引入外部文件,实现代码复用。


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

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

使用退出码

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

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

trap捕获信号

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

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

按Ctrl+C后,脚本会执行 cleanup 函数。

记录错误日志

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

bash 复制代码
#!/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内置功能:

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

2. 并行执行

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

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

3. 避免冗余操作

缓存重复使用的结果:

bash 复制代码
#!/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

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

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

bash 复制代码
#!/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

功能亮点

  • 模块化:将创建和删除逻辑封装为函数。
  • 错误处理:检查用户是否存在,记录失败日志。
  • 安全性:设置合理的目录权限。
相关推荐
虾..1 小时前
Linux 软硬链接和动静态库
linux·运维·服务器
Evan芙1 小时前
Linux常见的日志服务管理的常见日志服务
linux·运维·服务器
hkhkhkhkh1233 小时前
Linux设备节点基础知识
linux·服务器·驱动开发
HZero.chen4 小时前
Linux字符串处理
linux·string
张童瑶4 小时前
Linux SSH隧道代理转发及多层转发
linux·运维·ssh
汪汪队立大功1234 小时前
什么是SELinux
linux
石小千4 小时前
Linux安装OpenProject
linux·运维
柏木乃一4 小时前
进程(2)进程概念与基本操作
linux·服务器·开发语言·性能优化·shell·进程
Lime-30904 小时前
制作Ubuntu 24.04-GPU服务器测试系统盘
linux·运维·ubuntu
百年渔翁_肯肯5 小时前
Linux 与 Unix 的核心区别(清晰对比版)
linux·运维·unix