1. 主页 > 世界杯新浪 >

Shell 脚本调试终极技巧:set

Shell 脚本调试终极技巧:set -x 之外你还需要知道这些🐧 引言:你是不是也被 bash 折磨过?老实说,Shell 脚本是个“神奇”的东西:写起来简单,调起来想摔电脑。

我一开始写 shell 脚本的时候,基本靠“echo 大法”调试。加上 set -x,自以为天下无敌。直到有一次,脚本执行后变量莫名其妙为空、某个 if 判断永远不成立、死循环打爆了机器……

那天,我知道,单靠 set -x 是不够的。

今天这篇文章,我就带你看看 Shell 脚本调试的“终极技巧”,让你从“脚本黑洞”里杀出一条血路!

🎯 一、set -x 有多好用?但它不是万能的set -x 会在执行脚本时,把每一条命令及其参数“打印”出来,看起来像这样:

代码语言:bash复制$ bash debug.sh

+ name=Tom

+ echo Hello $name

Hello Tom这个功能非常适合:快速看出哪里出错、哪行没执行、变量值多少。

但它也有明显缺点:

打印信息太多,眼花缭乱;不会显示错误堆栈;遇到函数递归/子 shell 时不清晰;只显示执行,不显示变量声明细节。所以我说,它是个“万能放大镜”,但不是“全能探测仪”。

那我们接下来看看,还有哪些终极调试技巧。

🧠 二、echo 大法虽土,但真香这个方法你肯定用过,但你可能没用对。

很多人写成这样:

代码语言:bash复制echo $my_var但为了调试更清楚,建议你写成这样:

代码语言:bash复制echo "[DEBUG] my_var = '${my_var}'"这样做有几个好处:

'${var}' 可以看出变量是否为空;明确打上 [DEBUG] 标签,grep 更方便;更容易和生产日志区分。还有一个变种技巧:

代码语言:bash复制[ "$DEBUG" = "true" ] && echo "[DEBUG] result=$result"加上 DEBUG=true 环境变量后,你就能实现“开关式”调试,非常优雅。

🧩 三、set -e、set -u、set -o pipefail 组合拳,不调试也能避免问题这个组合我称它为 Shell 防呆三剑客:

代码语言:bash复制set -euo pipefail解释如下:

set -e:一旦脚本出错,立即退出;set -u:访问未定义变量时报错;set -o pipefail:管道命令中只要有一处失败就报错。例子:

代码语言:bash复制#!/bin/bash

set -euo pipefail

echo "Start"

cat /not/exist/file.txt # 立刻终止脚本

echo "End"你会发现这个脚本在找不到文件后不会继续往下执行,这对于避免误操作和追踪问题极其重要。

🔍 四、调试函数时,推荐用 declare -p 和 typeset -f你脚本里的函数是不是常常“调用没结果”?

这时试试下面这两个命令:

代码语言:bash复制declare -p # 打印变量类型和值

typeset -f # 显示所有函数定义示例:

代码语言:bash复制myfunc() {

local name="world"

echo "Hello, $name"

}

typeset -f myfunc这对于多人协作写脚本、查看函数结构非常有帮助,能直接定位函数定义位置。

📜 五、trap + DEBUG 信号,搞懂每一步执行了什么这是高手调试时经常用的黑科技:

代码语言:bash复制trap 'echo "[TRACE] $BASH_SOURCE:$LINENO - $BASH_COMMAND"' DEBUG它会在执行每一行命令前打印当前脚本路径、行号、即将执行的命令。

示例效果:

代码语言:bash复制[TRACE] ./debug.sh:3 - name="Jack"

[TRACE] ./debug.sh:4 - echo "Hello, $name"适合用来分析函数嵌套、分支逻辑错乱的问题。比 set -x 更直观,也更精细。

🧪 六、子 Shell 的陷阱:括号 () 会开新进程!很多人写脚本时喜欢加个括号,比如:

代码语言:bash复制(result=$(do_something))看起来很合理,但你要注意,这其实会开启一个子 Shell,主进程中修改的变量是拿不到的!

正确写法应该是:

代码语言:bash复制do_something

result=$?或者使用花括号块:

代码语言:bash复制{

echo "This runs in the same shell"

} # 不会开子 Shell所以调试变量“为什么明明赋值了但为空”,别忘了检查是不是子 Shell 在作怪!

🪵 七、推荐一个神器:shellcheck你有没有写过这种代码:

代码语言:bash复制if [ $var = "yes" ]; then但结果却报错,为什么?因为 $var 可能是空的,等于执行了:

代码语言:bash复制[ = "yes" ] # 报错这时你就需要 shellcheck ——一个 Shell 脚本静态检查神器。

安装方式(Ubuntu):

代码语言:bash复制sudo apt install shellcheck然后运行:

代码语言:bash复制shellcheck your_script.sh它会高亮你的语法错误、未定义变量、危险用法等,是写脚本必备工具。

🧯 八、我常用的调试套路最后总结一下我平时调脚本的“七步走”:

set -euxo pipefail 开头就加;全程加 [DEBUG] echo 打印关键变量;括号 () 开新 shell 别乱用;函数调试用 typeset -f;子进程 debug 用 trap '...' DEBUG;脚本提交前跑一遍 shellcheck;写完就让别人 review 一遍(防自己坑自己)。🧡 结语:不怕脚本出错,就怕你没招调试很多人说 Shell 脚本难,是因为错误太隐蔽、调试工具太原始。

但其实,只要掌握正确的调试思路和技巧,Shell 脚本也可以写得又稳又清晰。