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

news/2025/2/26 5:32:20

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

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

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

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

定义和调用函数

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

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

输出:

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

功能亮点

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

http://www.niftyadmin.cn/n/5868057.html

相关文章

android中的CheckBox改变背景图片显示大小

在androidStudio的xml文件设置布局时&#xff0c;对于checkBox选中后&#xff0c;展示大小不同的背景图片 1.首先需要一个选择器存放背景图片&#xff0c;设置选中和未选中状态 <?xml version"1.0" encoding"utf-8"?> <selector xmlns:androi…

嵌入式硬件篇---数字电子技术中的逻辑运算

、 文章目录 前言一、基本逻辑运算1. 与运算&#xff08;AND&#xff09;符号真值表功能应用 2. 或运算&#xff08;OR&#xff09;符号真值表功能应用 3. 非运算&#xff08;NOT符号真值表功能应用 4. 异或运算&#xff08;XOR&#xff09;符号真值表功能应用 5. 同或运算&…

全星FMEA软件系统是一款高效、智能的失效模式及影响分析工具,广泛应用于汽车、电子、机械等行业

全星FMEA软件系统是一款高效、智能的失效模式及影响分析工具&#xff0c;广泛应用于汽车、电子、机械等行业。该系统基于2019版FMEA手册开发&#xff0c;严格遵循七步方法&#xff0c;能够全面识别潜在风险并提前制定应对措施。 全星FMEA软件系统功能特点 自动化分析&#xff…

ubuntu20.04 突破文件数限制

增加文件描述符的限制 每个网络连接都占用一个文件描述符。增加文件描述符的数量&#xff0c;可以让系统处理更多的并发连接。 1.1 临时修改文件描述符限制 首先&#xff0c;查看当前的文件描述符限制&#xff1a; ulimit -n然后&#xff0c;将文件描述符限制增大&#xff0c…

Kafka 消费者组内分区分配策略 以及 管理控制台方案

一、Kafka 消费者组内分区分配策略 Kafka 通过 partition.assignment.strategy 参数控制消费者组内的分区分配策略&#xff0c;以下是主要策略及特点&#xff1a; 1. RangeAssignor&#xff08;默认策略&#xff09; partition.assignment.strategyorg.apache.kafka.clients…

9. grafana的bar gauge使用

1. 选择bar gauge 2. 填充数据源 3. 修改 Display 3. 在Field中的设置

Oracle 数据变化量查询

1. DBA_HIST_SEG_STAT可以看出对象的使用趋势&#xff0c;构造如下SQL查询出每个时间段内数据库对象的增长量 select c.SNAP_ID,to_char(c.END_INTERVAL_TIME, yyyy-mm-dd) SNAP_TIME,a.OWNER,a.OBJECT_NAME,a.OBJECT_TYPE,b.DB_BLOCK_CHANGES_DELTAfrom dba_objects a,(selec…

将VsCode变得顺手好用(1

目录 设置中文 配置调试功能 提效和增强相关插件 主题和图标相关插件 设置中文 打开【拓展】 输入【Chinese】 下载完成后重启Vs即可变为中文 配置调试功能 在随便一个位置新建一个文件夹&#xff0c;用于放置调试文件以及你未来写的代码&#xff0c;随便命名但切记不可用中…