Appearance
脚本优化
编写高效、健壮的 Shell 脚本需要从性能、可读性和可靠性多个维度进行优化。
性能优化
减少子进程创建
bash
# 慢:每次调用都 fork 子进程
for i in $(seq 1 1000); do
echo $i
done
# 快:使用内置语法
for (( i=1; i<=1000; i++ )); do
echo $i
done
# 慢:外部命令处理字符串
length=$(echo "$str" | wc -c)
# 快:使用参数扩展
length=${#str}减少管道层数
bash
# 慢:多个管道
cat file.txt | grep "error" | grep -v "warning" | wc -l
# 快:合并到单个命令
grep -c "error" file.txt
# 或者使用 awk 一次完成
awk '/error/ && !/warning/' file.txt | wc -l使用内置命令
bash
# 慢:外部命令
result=$(echo "$str" | tr 'a-z' 'A-Z')
# 快:Shell 内置(Bash 4+)
result="${str^^}"
# 慢
basename=$(echo "$path" | awk -F/ '{print $NF}')
# 快:参数扩展
basename="${path##*/}"避免在循环中执行昂贵操作
bash
# 慢:每次循环都调用 date
for file in *.log; do
timestamp=$(date +%Y%m%d)
mv "$file" "${file%.log}_${timestamp}.log"
done
# 快:只调用一次
timestamp=$(date +%Y%m%d)
for file in *.log; do
mv "$file" "${file%.log}_${timestamp}.log"
done可靠性优化
错误处理三件套
bash
#!/bin/bash
set -e # 遇到错误立即退出
set -u # 使用未定义变量时报错
set -o pipefail # 管道中任何命令失败都视为失败
# 简写
set -euo pipefail使用本地变量
bash
#!/bin/bash
# 不好:污染全局变量
process() {
result="处理结果"
temp_file="/tmp/temp$$"
}
# 好:使用 local
process() {
local result="处理结果"
local temp_file="/tmp/temp$$"
echo "$result"
}安全地处理文件名
bash
# 不好:文件名含空格会出错
for file in $(ls); do
cat $file
done
# 好:使用 glob 和双引号
for file in *; do
cat "$file"
done
# 处理特殊字符开头的文件名
for file in ./*; do
cat "$file"
done临时文件安全处理
bash
#!/bin/bash
# 使用 mktemp 创建安全的临时文件
temp_file=$(mktemp /tmp/myapp_XXXXXX.tmp)
temp_dir=$(mktemp -d /tmp/myapp_XXXXXX)
# 注册清理
trap 'rm -f "$temp_file"; rm -rf "$temp_dir"' EXIT INT TERM
echo "处理数据..." > "$temp_file"可读性优化
有意义的变量名
bash
# 不好
t=$(date +%s)
for f in /var/log/*.log; do
s=$(stat -c %s "$f")
if (( s > 1000000 )); then
echo "$f"
fi
done
# 好
current_timestamp=$(date +%s)
max_log_size=1000000
for log_file in /var/log/*.log; do
file_size=$(stat -c %s "$log_file")
if (( file_size > max_log_size )); then
echo "大文件:$log_file(${file_size} 字节)"
fi
done提取函数
bash
#!/bin/bash
# 不好:所有逻辑堆在一起
# ...200 行脚本...
# 好:拆分为函数
setup_environment() {
export APP_HOME="/opt/myapp"
export APP_LOG="$APP_HOME/logs"
mkdir -p "$APP_LOG"
}
check_dependencies() {
for cmd in curl jq awk; do
command -v "$cmd" >/dev/null 2>&1 || {
echo "缺少依赖:$cmd" >&2
exit 1
}
done
}
main() {
setup_environment
check_dependencies
# 主逻辑...
}
main "$@"脚本头部规范
bash
#!/usr/bin/env bash
#
# 脚本名称:deploy.sh
# 功能描述:自动化部署脚本
# 作者:运维团队
# 创建日期:2025-01-01
# 使用方法:./deploy.sh [环境] [版本]
# 示例:./deploy.sh production v1.2.3
#
set -euo pipefail
# 常量定义
readonly SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
readonly SCRIPT_NAME="$(basename "$0")"
readonly LOG_FILE="/var/log/${SCRIPT_NAME%.sh}.log"
# 日志函数
log() { echo "[$(date '+%Y-%m-%d %H:%M:%S')] $*" | tee -a "$LOG_FILE"; }
error() { log "ERROR: $*" >&2; exit 1; }
# 参数验证
[[ $# -lt 2 ]] && error "用法:$SCRIPT_NAME <环境> <版本>"调试优化
bash
#!/bin/bash
# 开启调试模式
set -x # 打印每条执行的命令
# 只调试特定代码段
set -x
# 需要调试的代码...
set +x
# 使用环境变量控制调试
[[ "${DEBUG:-}" == "1" ]] && set -x
# 输出带行号的错误信息
err_line() {
echo "错误发生在第 ${BASH_LINENO[0]} 行" >&2
}
trap err_line ERR兼容性优化
bash
#!/usr/bin/env bash
# 使用 env 查找 bash,提高可移植性
# 检测 Shell 版本
if (( BASH_VERSINFO[0] < 4 )); then
echo "需要 Bash 4.0 以上版本" >&2
exit 1
fi
# 使用 POSIX 兼容语法(若需要在 sh 下运行)
# 避免使用:[[ ]]、(( ))、{a..z}、数组等 Bash 特性