如何在 Linux 上捕获 Bash 脚本中的错误如何在 Linux 上捕获 Bash 脚本中的错误如何在 Linux 上捕获 Bash 脚本中的错误如何在 Linux 上捕获 Bash 脚本中的错误
  • 文章
  • 正则表达式
    • 工具
  • 登录
找到的结果: {phrase} (显示: {results_count} 共: {results_count_total})
显示: {results_count} 共: {results_count_total}

加载更多搜索结果...

搜索范围
模糊匹配
搜索标题
搜索内容
发表 admin at 2025年2月28日
类别
  • 未分类
标签

如何在 Linux 上捕获 Bash 脚本中的错误

默认情况下,Linux 上的 Bash 脚本会报告错误但会继续运行。我们向您展示了如何自己处理错误,以便您可以决定下一步需要做什么。

脚本中的错误处理

处理错误是编程的一部分。即使您编写了完美的代码,您仍然会遇到错误情况。随着您安装和卸载软件、创建目录以及执行升级和更新,您计算机上的环境会随着时间的推移而发生变化。

例如,如果目录路径发生变化或文件权限发生变化,过去正常运行的脚本可能会遇到困难。 Bash shell 的默认操作是打印错误消息并继续执行脚本。这是一个危险的默认值。

如果失败的操作对于脚本中稍后发生的某些其他处理或操作至关重要,则该关键操作将不会成功。结果会有多大的灾难性取决于您的脚本试图做什么。

一个更健壮的方案将检测错误并让脚本在需要关闭或尝试修复故障情况时运行。例如,如果目录或文件丢失,让脚本重新创建它们可能会令人满意。

如果脚本遇到无法恢复的问题,它可以关闭。如果脚本必须关闭,它可以有机会执行所需的任何清理工作,例如删除临时文件或将错误情况和关闭原因写入日志文件。

检测退出状态

命令和程序生成一个值,在它们终止时发送到操作系统。这称为他们的退出状态。如果没有错误,它的值为零,如果发生错误,它的值为非零值。

我们可以检查脚本使用的命令的退出状态(也称为返回码),并确定命令是否成功。

在 Bash 中,零等于真。如果命令的响应不是 true,我们就知道发生了问题,我们可以采取适当的措施。

将此脚本复制到编辑器中,并将其保存到名为“bad_command.sh”的文件中。

#!/bin/bash

if ( ! bad_command ); then
  echo "bad_command flagged an error."
  exit 1
fi

您需要使用 chmod 命令使脚本可执行。这是使任何脚本可执行所需的步骤,因此如果您想在自己的计算机上试用脚本,请记住对每个脚本都执行此操作。在每种情况下替换适当脚本的名称。

chmod +x bad_command.sh

当我们运行脚本时,我们会看到预期的错误消息。

./bad_command.sh

没有“bad_command”这样的命令,也不是脚本中的函数名称。它无法执行,因此响应不为零。如果响应不为零——这里使用感叹号作为逻辑 NOT 运算符——执行 if 语句的主体。

在真实世界的脚本中,这可能会终止脚本(我们的示例会这样做),或者它可能会尝试修复错误情况。

exit 1 行可能看起来是多余的。毕竟,脚本中没有其他内容,无论如何它都会终止。但是使用 exit 命令允许我们将退出状态传递回 shell。如果我们的脚本在第二个脚本中被调用,第二个脚本就会知道这个脚本遇到了错误。

您可以对命令的退出状态使用逻辑 OR 运算符,如果第一个命令的响应非零,则调用脚本中的另一个命令或函数。

command_1 || command_2

这是有效的,因为第一个命令运行 OR 第二个。最左边的命令首先运行。如果成功,则不执行第二个命令。但是,如果第一个命令失败,则执行第二个命令。所以我们可以这样构造代码。这是“逻辑或./sh”。

#!/bin/bash

error_handler()
{
  echo "Error: ($?) $1"
  exit 1
}

bad_command || error_handler "bad_command failed, Line: ${LINENO}"

我们定义了一个名为 error_handler 的函数。这会打印出失败命令的退出状态,保存在变量 $? 中,以及调用函数时传递给它的一行文本。这保存在变量 $1 中。该函数以 1 的退出状态终止脚本。

该脚本尝试运行 bad_command,但显然失败了,因此执行逻辑 OR 运算符右侧的命令 ||。这将调用 error_handler 函数并传递一个字符串,该字符串命名失败的命令,并包含失败命令的行号。

我们将运行脚本以查看错误处理程序消息,然后使用 echo 检查脚本的退出状态。

./logical-or.sh
echo $?

我们的小 error_handler 函数提供尝试运行 bad_command 的退出状态、命令名称和行号。当您调试脚本时,这是有用的信息。

脚本的退出状态是一个。 error_handler 报告的 127 退出状态表示“找不到命令”。如果需要,我们可以将其传递给 exit 命令,以此作为脚本的退出状态。

另一种方法是扩展 error_handler 以检查退出状态的不同可能值并相应地执行不同的操作,使用这种类型的构造:

exit_code=$?

if [ $exit_code -eq 1 ]; then
  echo "Operation not permitted"

elif [ $exit_code -eq 2 ]; then
  echo "Misuse of shell builtins"
.
.
.
elif [ $status -eq 128 ]; then
  echo "Invalid argument"
fi

使用 set 强制退出

如果您知道您希望脚本在出现错误时退出,您可以强制它这样做。这意味着你放弃了任何清理的机会——或者任何进一步的破坏——因为你的脚本一旦检测到错误就会终止。

为此,请使用带有 -e(错误)选项的 set 命令。这告诉脚本在命令失败或返回大于零的退出代码时退出。此外,使用 -E 选项可确保在 shell 函数中进行错误检测和捕获。

要同时捕获未初始化的变量,请添加 -u(未设置)选项。要确保在管道序列中检测到错误,请添加 -o pipefail 选项。如果没有这个,管道命令序列的退出状态就是序列中final命令的退出状态。管道序列中间的失败命令将不会被检测到。 -o pipefail 选项必须出现在选项列表中。

添加到脚本顶部的顺序是:

set -Eeuo pipefail

这是一个名为“unset-var.sh”的简短脚本,其中包含一个未设置的变量。

#!/bin/bash

set -Eeou pipefail

echo "$unset_variable"

echo "Do we see this line?"

当我们运行脚本时,unset_variable 被识别为未初始化的变量,脚本终止。

./unset-var.sh

第二个 echo 命令永远不会执行。

使用有错误的陷阱

Bash trap 命令允许您指定在发出特定信号时应调用的命令或函数。通常,这用于捕获信号,例如 SIGINT,当您按下 Ctrl+C 组合键时会发出该信号。这个脚本是“sigint.sh”。

#!/bin/bash

trap "echo -e '\nTerminated by Ctrl+c'; exit" SIGINT

counter=0

while true
do 
  echo "Loop number:" $((++counter))
  sleep 1
done

trap 命令包含一个 echo 命令和一个 exit 命令。当 SIGINT 被引发时,它将被触发。脚本的其余部分是一个简单的循环。如果您运行脚本并按 Ctrl+C,您将看到来自 trap 定义的消息,脚本将终止。

./sigint.sh

我们可以将 trap 与 ERR 信号一起使用,以在错误发生时捕获它们。然后可以将这些提供给命令或功能。这是“trap.sh”。我们正在向一个名为 error_handler 的函数发送错误通知。

#!/bin/bash

trap 'error_handler $? $LINENO' ERR

error_handler() {
  echo "Error: ($1) occurred on $2"
}

main() {
  echo "Inside main() function"
  bad_command
  second
  third
  exit $?
}

second() {
  echo "After call to main()"
  echo "Inside second() function"
}

third() {
  echo "Inside third() function"
}

main

大部分脚本位于 main 函数内,它调用 second 和 third 函数。当遇到错误时——在这种情况下,因为 bad_command 不存在——trap 语句将错误定向到 error_handler 函数。它将失败命令的退出状态和行号传递给 error_handler 函数。

./trap.sh

我们的 error_handler 函数只是将错误的详细信息列出到终端窗口。如果需要,您可以向函数添加 exit 命令以终止脚本。或者您可以使用一系列 if/elif/fi 语句来针对不同的错误执行不同的操作。

可能可以修复一些错误,其他错误可能需要脚本停止。

最后的提示

捕获错误通常意味着预先排除可能出错的事情,并在它们出现时编写代码来处理这些意外事件。除此之外,还要确保脚本的执行流程和内部逻辑正确无误。

如果您使用此命令运行脚本,Bash 将在脚本执行时向您显示跟踪输出:

bash -x your-script.sh

Bash 在终端窗口中写入跟踪输出。它显示每个命令及其参数(如果有的话)。这发生在命令展开之后但执行之前。

它可以极大地帮助追踪难以捉摸的错误。

©2015-2025 艾丽卡 support@alaica.com