简介
想象一下:每次你请别人完成一项工作,对方都会在完成后交给你一张小卡片。
- 绿卡(0)表示「我已完美完成」。
- 红卡(1-255)表示「出了问题」。
在 Linux 中,每条命令都会这样做。这称为退出码或退出状态。
0:成功。Not 0:失败。
除非主动查看,大多数情况下这些代码是不可见的,因此初学者经常忽略它们。专业脚本开发者会密切关注退出码,因为退出状态是 Shell 在命令和脚本之间报告成功或失败的主要方式之一。
这是 Unix 的核心设计模式:小型程序通过简单的约定彼此通信。文本可以通过标准输出传递,成功或失败则通过退出状态传递。这就是退出码在自动化任务中如此重要的原因。
在本实验中,你将学习如何使用变量 $? 读取这些秘密卡片,并在脚本出错前及时停止脚本。
使用 $? 检查命令状态
如何查看这个不可见的「成绩卡」?运行命令后,立即查看名为 $? 的特殊变量。
先查看命令成功时的情况。
打开终端,列出文件:
ls -l
命令成功执行了,对吧?现在查看「得分」:
echo $?
你应该会看到 0。按照 Linux 的逻辑,0 表示错误数量为 0。没有错误就表示完全成功。
现在强制制造一次失败。尝试列出不存在的文件:
ls ghosts.txt
Linux 会提示找不到该文件。现在再次查看得分:
echo $?
你会看到 2。它不是 0,因此表示失败。
具体的非零数字会因命令和情况而有所不同,但现在只需记住一个关键规则:0 表示成功,其他任何值都表示失败。之后使用脚本和工具时,你会看到有些程序会使用不同的非零退出码来表示不同类型的问题。
关键规则:$? 是短期记忆。它只记住你刚刚执行的最后一项操作。如果你先运行 ls(失败),再运行 echo "hello",最后查看 $?,你会看到 0,因为 echo 执行成功了!你必须立即检查 $?。
创建一个会失败的脚本
这里就是危险所在。默认情况下,脚本会忽略红卡,继续执行后续命令。
想象一个脚本执行以下操作:
- 创建备份。
- 删除原始文件。
如果第 1 步失败了(备份空间已满),第 2 步仍然会执行,你就会丢失所有文件。
现在模拟这个「盲目脚本」。
创建 copy_script.sh:
nano copy_script.sh
输入以下代码。它会尝试复制一个不存在的文件,然后声称操作成功。
#!/bin/bash
## Attempt to copy a ghost
cp ghost_file.txt destination.txt
## Print a happy message
echo "Script finished execution"
保存并退出。为脚本添加可执行权限:
chmod +x copy_script.sh
运行脚本:
./copy_script.sh
你会看到 cp 输出的错误信息,但随后又会看到「Script finished execution」。脚本虽然出错了,却仍然继续执行!
查看脚本本身的得分:
echo $?
它返回 0。为什么?因为最后一条命令(echo)执行成功了。这个脚本在说谎:它没有完成主要任务,却向系统报告了成功。
这是一个重要的经验:Shell 脚本也有退出状态。如果你不进行特殊处理,它通常会使用最后执行的命令的退出状态。因此,脚本可能会意外隐藏之前发生的错误。
实现错误处理
现在需要让脚本在遇到红灯时停止。
通常可以使用以下结构:「尝试执行命令 X。如果退出码不为 0,就立即处理错误。」
语法 [ $? -ne 0 ] 使用了 test 命令,这里采用方括号形式书写。-ne 表示数字「不等于」。因此,Shell 实际上是在询问:「上一条命令的退出状态是否不等于零?」
编辑脚本 copy_script.sh:
nano copy_script.sh
将内容修改为:
#!/bin/bash
cp ghost_file.txt destination.txt
## Check if the score is NOT equal (-ne) to 0
if [ $? -ne 0 ]; then
echo "Error: The copy operation failed!"
exit 1
fi
echo "Script finished execution"
代码说明:
if [ $? -ne 0 ]:检查退出码的条件。exit 1:红色按钮。它会立即终止脚本,并将全局得分设为 1(错误)。
exit 命令会结束当前 Shell 脚本,并将指定的数字返回给启动它的对象,例如终端、其他脚本或自动化系统。换句话说,它不仅会在当前脚本中停止执行,还会向外部报告状态。
保存并退出。
再次运行脚本:
./copy_script.sh
脚本会输出错误信息并终止,不会输出「Script finished execution」。
查看得分:
echo $?
结果是 1。现在,脚本能够如实报告自己的失败状态。
总结
你已经学会了如何理解命令的秘密语言。
在本实验中,你练习了:
- 读取成绩卡:使用
$?查看命令是成功(0)还是失败(1-255)。 - 揭穿谎言:了解脚本在处理不当时如何隐藏错误。
- 充当裁判:使用
exit 1,在发生错误时停止脚本。
这种「检查并退出」模式,是脆弱脚本与专业脚本之间的区别。



