Skip to content

脚本工程、调试与 Bash 扩展

  • 状态:已验证
  • 来源:对话整理
  • 更新时间:2026-03-12

关键结论

  • 脚本工程部分应优先覆盖路径处理、参数解析、调试、trap、后台进程和常见模板。
  • Bash 扩展如模式匹配、正则、进程替换和 shopt 很实用,但必须明确 Bash 依赖。

详细分析

  • 大多数可维护性问题不是语法本身,而是脚本目录定位、参数处理、错误定位和清理逻辑缺失。
  • set -xtrapgetopts 和进程控制是排查复杂脚本问题的高频工具。

可执行步骤

  1. 在脚本开头先确定脚本目录、严格模式和清理机制。
  2. 使用 getopts 处理短参数。
  3. 遇到问题时先用 set -xbash -x 观察执行过程。
  4. 使用 Bash 扩展前,确保脚本明确声明 Bash 依赖。

命令 / 配置 / 代码

脚本工程

高频写法清单:

  • SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
  • trap '...' EXIT
  • while getopts ":f:o:h" opt; do ... done
  • set -x
  • bash -x script.sh
  • cmd &
  • wait "$pid"

路径与脚本目录

  • "$(dirname "$0")" 获取脚本路径的目录部分。
  • "${BASH_SOURCE[0]}" 当前 Bash 脚本文件路径。
  • "$(cd ... && pwd)" 获取绝对路径。
bash
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
ROOT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"

Bash 扩展

高频写法清单:

  • [[ "$x" == *.sh ]]
  • [[ "$x" =~ regex ]]
  • <(cmd)
  • >(cmd)
  • shopt -s nullglob
  • shopt -s globstar

通配符与模式匹配

  • * 匹配任意长度字符。
  • ? 匹配单个字符。
  • [abc] 匹配字符集合中的任一字符。
  • [a-z] 匹配字符范围。
  • [[ "$x" == *.md ]] 在 Bash 条件中进行模式匹配。
bash
for f in *.md; do
  echo "$f"
done

if [[ "$file" == *.sh ]]; then
  echo "shell script"
fi

正则匹配

  • [[ "$x" =~ regex ]] 使用 Bash 正则进行匹配。
  • ${BASH_REMATCH[0]} 完整匹配内容。
  • ${BASH_REMATCH[1]} 第一个捕获组。
bash
text="user:1001"
if [[ "$text" =~ ^([a-z]+):([0-9]+)$ ]]; then
  echo "${BASH_REMATCH[1]}"
  echo "${BASH_REMATCH[2]}"
fi

模板

高频写法清单:

  • 参数数量校验
  • 文件存在性校验
  • 临时文件清理
  • trap ... EXIT

常见写法模板

bash
if [ $# -lt 1 ]; then
  echo "usage: $0 <file>"
  exit 1
fi
bash
if [ ! -f "$1" ]; then
  echo "file not found: $1"
  exit 1
fi
bash
trap 'echo "cleanup"; rm -f "$tmp_file"' EXIT

trap 与信号处理

  • trap 'cmd' EXIT 脚本退出时执行清理命令。
  • trap 'cmd' INT 捕获 Ctrl+C
  • trap - EXIT 清除已设置的 trap。
bash
tmp_file="$(mktemp)"
trap 'rm -f "$tmp_file"' EXIT

进程与后台执行

  • cmd & 后台执行命令。
  • wait 等待所有后台任务结束。
  • wait "$pid" 等待指定进程。
  • jobs 查看当前 shell 后台任务。
  • kill "$pid" 向指定进程发送信号。
bash
sleep 10 &
pid="$!"
echo "$pid"
wait "$pid"

常用内建命令

  • echo 输出文本。
  • printf 格式化输出,通常比 echo 更稳定。
  • read 读取输入。
  • test 条件测试,等价于 [ ... ]
  • shift 左移位置参数。
  • export 导出环境变量。
  • declare 声明变量属性。
bash
printf '%s\n' "$name"
export APP_ENV=prod
shift

参数解析与 getopts

  • while getopts ":f:o:h" opt; do ... done 解析短选项参数。
  • OPTARG 当前选项携带的参数值。
  • OPTIND 下一个待处理参数的索引。
  • shift $((OPTIND - 1)) 移除已经解析过的选项参数。
bash
file=""
output=""

while getopts ":f:o:h" opt; do
  case "$opt" in
    f) file="$OPTARG" ;;
    o) output="$OPTARG" ;;
    h)
      echo "usage: $0 -f <file> -o <output>"
      exit 0
      ;;
    :)
      echo "option requires an argument: -$OPTARG"
      exit 1
      ;;
    \?)
      echo "invalid option: -$OPTARG"
      exit 1
      ;;
  esac
done

shift $((OPTIND - 1))

调试与排错

  • set -x 打开执行跟踪,打印每条执行命令。
  • set +x 关闭执行跟踪。
  • set -v 输出 shell 读取到的脚本原文。
  • bash -x script.sh 以调试模式执行脚本。
  • trap '...' ERR 命令出错时执行错误处理逻辑。
  • PS4='+ ${BASH_SOURCE}:${LINENO}: ' 自定义 set -x 的调试输出前缀。
bash
set -x
echo "debug"
set +x
bash
PS4='+ ${BASH_SOURCE}:${LINENO}: '
set -x
bash
trap 'echo "error on line $LINENO"' ERR
set -e

进程替换

  • <(cmd) 将命令输出伪装成一个可读取的文件路径。
  • >(cmd) 将输出重定向到某个命令的输入。
bash
diff <(sort a.txt) <(sort b.txt)
bash
echo "hello" > >(tee output.txt)

shell 选项与 shopt

  • set -o 查看或设置 shell 选项。
  • set +o 以可重放形式输出当前选项。
  • shopt 查看或设置 Bash 扩展选项。
  • shopt -s nullglob 开启某个 Bash 扩展选项。
  • shopt -u nullglob 关闭某个 Bash 扩展选项。
bash
set -o
set +o
shopt
bash
shopt -s nullglob
files=(*.md)
shopt -u nullglob

风险与注意事项

  • getopts 主要处理短选项,复杂长选项解析通常需要额外逻辑。
  • 打开 set -x 时,敏感信息可能被直接打印到日志或终端。
  • <(cmd)>(cmd)[[ ... ]]、数组和 shopt 都依赖 Bash,不应误标为通用 sh 语法。