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

功能亮点

  • 模块化:将创建和删除逻辑封装为函数。
  • 错误处理:检查用户是否存在,记录失败日志。
  • 安全性:设置合理的目录权限。
相关推荐
想学好C++的oMen12 分钟前
进程状态(R|S|D|t|T|X|Z)、僵尸进程及孤儿进程
linux·ubuntu
i建模2 小时前
windows下访问linux,unix终端工具选型
linux·windows·unix
网络安全-杰克2 小时前
网络安全 linux学习计划 linux网络安全精要
linux·学习·web安全
局外人_Jia3 小时前
【C# 变量字符串还原转义字符】
linux·数据库·windows·正则表达式·c#·字符串·indexof
m0_751018664 小时前
ubuntu-server 安装 navidia 显卡驱动
linux·运维·ubuntu
End9284 小时前
VMware中的linux常用指令
linux·运维·服务器
梦游钓鱼4 小时前
使用virtualenv遇到的问题,工具冲突
linux·python·virtualenv
H轨迹H4 小时前
VulnHub-DC-6靶机-wpscan爆破+命令注入反弹shell+nmap提权
linux·网络安全·渗透测试·vulnhub·靶机
仙八哥5 小时前
Ubuntu搭建esp32环境 配置打开AT指令集 websocket功能
linux·websocket·ubuntu
网络安全指导员6 小时前
Linux网络安全
linux·运维·web安全