当前位置: 首页 > news >正文

Shell 脚本调试技巧:让 Bash 脚本不再神秘报错

Shell 脚本调试技巧让 Bash 脚本不再神秘报错写 Shell 脚本最烦的就是脚本跑到一半无声失败或者报错信息完全看不懂。掌握几个调试技巧能把脚本调试效率提升几倍。这篇文章总结生产环境实用的 Shell 调试方法调试模式、错误处理、日志记录、性能分析。基础调试模式set 选项最常用#!/bin/bash# 最佳实践在脚本开头加这三行set-euopipefail# 解释# -e → 任何命令失败返回非0立即退出脚本# -u → 使用未定义的变量时报错退出# -o pipefail → 管道中任何命令失败整个管道就失败为什么重要# 不加 set -e 的坑rm-rf$DIR/*# 如果 $DIR 为空变成 rm -rf /*# 加 set -eu 后DIRrm-rf$DIR/*# → 报错DIR: unbound variable立即退出-x 模式执行追踪#!/bin/bashset-x# 打印每条命令执行前的内容echoHello# 输出# echo Hello# HelloVARworldecho$VAR# 输出# VARworld# echo world# world临时对某段代码开启调试#!/bin/bashecho正常模式set-x# 这里的命令会被追踪complicated_functionsetxecho关闭追踪后-v 模式脚本行追踪bash-vscript.sh# 打印每行脚本内容执行前bash-xvscript.sh# 同时开启 -x 和 -v错误处理最佳实践trap 捕获退出信号#!/bin/bashset-euopipefail# 创建临时文件TMPFILE$(mktemp)# 无论脚本如何退出都执行清理cleanup(){localexit_code$?echo退出清理临时文件...rm-f$TMPFILEexit$exit_code}trapcleanup EXIT# 捕获错误打印出错位置err_handler(){echo错误发生在第$BASH_LINENO行$BASH_COMMANDecho退出码$?}traperr_handler ERR# 正常的脚本逻辑echo临时文件$TMPFILE# 哪怕脚本中途 CtrlC临时文件也会被清理自定义错误函数#!/bin/bash# 颜色输出RED\033[0;31mGREEN\033[0;32mYELLOW\033[1;33mNC\033[0m# 无颜色log_info(){echo-e${GREEN}[INFO]${NC}$*;}log_warn(){echo-e${YELLOW}[WARN]${NC}$*;}log_error(){echo-e${RED}[ERROR]${NC}$*2;}# 错误输出到 stderrdie(){log_error$exit1}# 使用log_info开始部署...command_might_fail||die部署失败请检查日志log_info部署成功日志记录同时输出到终端和日志文件#!/bin/bashLOG_FILE/var/log/myapp/deploy-$(date%Y%m%d_%H%M%S).logmkdir-p$(dirname$LOG_FILE)# 把所有输出stdout stderr同时写到文件和终端exec(tee-a$LOG_FILE)21echo 部署开始$(date)# 之后所有 echo 和命令输出都会同时出现在终端和日志文件里带时间戳的日志函数log(){echo[$(date%Y-%m-%d %H:%M:%S)]$*}log开始备份数据库...pg_dump mydbbackup.sql log备份完成变量调试# 查看变量值echo变量值${MY_VARQ}# Q 带引号输出显示特殊字符# 查看数组内容echo数组${MY_ARRAY[]Q}# 追踪变量赋值bash 4.4declare-tMY_VAR# 每次赋值时打印 trace# 检查变量是否为空if[[-z${MY_VAR:-}]];thenecho变量为空fi# 带默认值变量为空时用默认值NAME${USER_INPUT:-默认值}函数调试# 打印调用栈print_stack(){locali0localFRAMES${#FUNCNAME[]}echo调用栈从最内层到最外层for((i1;iFRAMES;i));doecho [$i]${BASH_SOURCE[$i]}:${BASH_LINENO[$i-1]}${FUNCNAME[$i]}done}my_function(){print_stack# 在函数里调用查看是谁调了我# ...}性能分析找出脚本哪里慢#!/bin/bash# 方法一time 命令time./long-script.sh# 方法二在脚本内计时start_time$(date%s%N)expensive_operationend_time$(date%s%N)elapsed$(((end_time-start_time)/1000000))echo耗时${elapsed}ms# 方法三PS4 变量配合 set -xexportPS4 [${BASH_SOURCE##*/}:${LINENO}] set-x# 现在追踪输出会显示文件名和行号常见陷阱和解决方法# 陷阱1空格问题FILEmy file.txtif[-f$FILE];then# 错$FILE 会被分成两个参数if[-f$FILE];then# 正确加引号# 陷阱2命令替换里的错误被忽略OUTPUT$(false_command)# 不会触发 set -eOUTPUT$(false_command)||exit1# 显式处理# 陷阱3grep 的退出码greppatternfile# 没找到返回 1会触发 set -egreppatternfile||true# 没找到也不退出# 陷阱4比较数字用 ((...))不要用 [ ]if[$NUM10];then# 错 是重定向会创建文件10if((NUM10));then# 正确算术比较# 陷阱5for 循环遍历文件forfilein$(ls*.txt);do# 错空格和换行会出问题forfilein*.txt;do# 正确直接用 glob使用 shellcheck 静态检查# 安装sudoaptinstall-yshellcheck# 检查脚本shellcheckmy-script.sh# 常见警告# SC2086: Double quote to prevent globbing# SC2006: Use $(...) instead of legacy ...# SC2046: Quote this to prevent word splitting# 在 VS Code 里安装 ShellCheck 插件实时检查一个完整的脚本模板#!/bin/bash# 描述做什么事# 用法./script.sh [参数]set-euopipefail# 常量readonlySCRIPT_DIR$(cd $(dirname${BASH_SOURCE[0]})pwd) readonly SCRIPT_NAME$(basename${BASH_SOURCE[0]}) readonly LOG_FILE/tmp/${SCRIPT_NAME%.*}-$(date%Y%m%d).log # 日志函数 log() { echo [$(date%H:%M:%S)]INFO$* | tee -a $LOG_FILE; } warn() { echo [$(date%H:%M:%S)]WARN$* | tee -a $LOG_FILE 2; } error() { echo [$(date%H:%M:%S)]ERROR$* | tee -a $LOG_FILE 2; } die() { error $; exit 1; } # 清理 cleanup() { log 脚本退出; } trap cleanup EXIT # 参数检查 usage() { echo 用法$SCRIPT_NAME[选项] echo -h显示帮助 exit 0 } while getopts h opt; do case$optin h) usage ;; *) die 未知参数 ;; esac done # 主逻辑 main() { log 开始执行... log 完成 } main $良好的 Shell 调试习惯能节省大量排查时间。set -euo pipefailtrap错误处理 shellcheck静态检查是生产环境 Shell 脚本的三件套。在雨云服务器 rainyuncom上跑的自动化脚本备份、部署、监控加上这些调试技巧出了问题马上定位注册填优惠码2026off领 5 折优惠券稳定可靠的服务器加上可靠的脚本是运维自动化的基础。
http://www.rkmt.cn/news/1294914.html

相关文章:

  • 台州寒雪制冷设备:台州速冻库定制哪家好 - LYL仔仔
  • C++ mutable关键字:逻辑常量性与线程安全缓存实战解析
  • 告别环境配置焦虑:用Intel oneAPI和OpenMPI在CentOS7搭建你的第一个并行计算Demo
  • Harness Open Source 与 GitLab 的区别:一个轻量一体化 DevOps 平台,一个完整 DevSecOps 平台
  • 基于ESP32与WLED打造智能可编程灯饰:从硬件连接到软件配置全攻略
  • 保姆级教程:在Ubuntu 22.04上给Tesla M40/P40装NVIDIA驱动(含禁用nouveau完整流程)
  • 2026天津春考择校指南:哪家培训学校的就业率更靠谱?
  • 通过OpenClaw配置Taotoken作为Agent底层模型的详细过程
  • 电解电容核心参数详解:从选型到实战,硬件工程师必读
  • 宝珀手表“体力不支”了?无锡宝珀腕表动力储存变短是什么原因?一位表主的破案实录 - 亨得利官方维修中心
  • 蓝桥杯嵌入式组 历年客观题高频考点与实战解析
  • 嵌入式调试革命:J-Probe实时可视化交互工具实战指南
  • 从零构建智能语音照明系统:硬件选型、电路设计与软件实现全解析
  • Windows 10终极清理指南:如何用Windows10Debloater一键移除系统垃圾应用
  • Ryujinx完整指南:如何安装和使用这款开源Switch模拟器
  • 书匠策AI到底藏了什么黑科技?拆解完它的毕业论文功能我愣住了
  • 手把手教你:用Edge/Chrome浏览器把Jupyter Notebook作业直接保存为PDF(含画布大小调整技巧)
  • 如何快速上手小米手表表盘设计:免费工具Mi-Create的终极指南
  • 苹果手机照片去背景怎么操作?iOS照片去背景方法2026实测对比
  • DataX实战避坑:用Shell脚本+JSON模板搞定MySQL多表同步,别再手动复制粘贴了
  • IEEE PHM 2012 轴承退化数据挑战:从原始振动信号到RUL预测实战
  • 如何在macOS上运行Windows程序:Whisky完整指南
  • 2026年陕西防火门防盗门工程采购指南:新中意门业与主流品牌深度横评 - 年度推荐企业名录
  • PDF怎么拼接合并?2026最实用的免费工具和方法盘点 - AI测评专家
  • Claude Code出质量事故了?Anthropic发了一篇有诚意的复盘|AI新岗位FDE爆火
  • G-Helper:为华硕笔记本用户打造的轻量级控制伴侣
  • 从网工视角看华为eSight:除了管网络,它如何统一管理服务器、存储和虚拟化资源?
  • 内存查看器原理与应用:从进程内存读取到调试实战
  • 【职场】职场里,离开那个平台,你还剩下什么
  • C++11原子操作详解