发生错误时如何在 Bash 中找到行号?

yae*_*ael 35 linux scripting bash logs shell-script

如何在 Bash 中找到发生错误的行号?

例子

我创建了以下带有行号的简单脚本来解释我们需要什么。该脚本将从中复制文件

cp $file1 $file2
cp $file3 $file4
Run Code Online (Sandbox Code Playgroud)

当其中一个cp命令失败时,该函数将以exit 1 退出。我们希望向函数添加还打印带有行号(例如,8 或 12)的错误的功能。

这可能吗?

示例脚本

1 #!/bin/bash
2
3
4 function in_case_fail {
5 [[ $1 -ne 0 ]] && echo "fail on $2" && exit 1
6 }
7
8 cp $file1 $file2
9 in_case_fail $? "cp $file1 $file2"
10
11
12 cp $file3 $file4
13 in_case_fail $? "cp $file3 $file4"
14
Run Code Online (Sandbox Code Playgroud)

slm*_*slm 44

与其使用您的函数,不如使用此方法:

$ cat yael.bash
#!/bin/bash

set -eE -o functrace

file1=f1
file2=f2
file3=f3
file4=f4

failure() {
  local lineno=$1
  local msg=$2
  echo "Failed at $lineno: $msg"
}
trap 'failure ${LINENO} "$BASH_COMMAND"' ERR

cp -- "$file1" "$file2"
cp -- "$file3" "$file4"
Run Code Online (Sandbox Code Playgroud)

这是通过捕获 ERR 然后failure()使用当前行号 + 执行的 bash 命令调用函数来工作的。

例子

在这里,我没有注意创建文件f1、f2、f3、 或f4。当我运行上面的脚本时:

$ ./yael.bash
cp: cannot stat ‘f1’: No such file or directory
Failed at 17: cp -- "$file1" "$file2"
Run Code Online (Sandbox Code Playgroud)

它失败,报告已执行的行号加命令。


ilk*_*chu 17

除了LINENO包含当前行号之外,还有BASH_LINENOand FUNCNAME(and BASH_SOURCE) 数组包含调用它们的函数名称和行号。

所以你可以做这样的事情:

#!/bin/bash

error() {
        printf "'%s' failed with exit code %d in function '%s' at line %d.\n" "${1-something}" "$?" "${FUNCNAME[1]}" "${BASH_LINENO[0]}"
}

foo() {
        ( exit   0 ) || error "this thing"
        ( exit 123 ) || error "that thing"
}

foo
Run Code Online (Sandbox Code Playgroud)

运行会打印

'that thing' failed with exit code 123 in function 'foo' at line 9.
Run Code Online (Sandbox Code Playgroud)

如果您使用set -e, 或trap ... ERR自动检测错误,请注意它们有一些警告。包含脚本当时正在做什么的描述也更难(就像您在示例中所做的那样),尽管这对普通用户来说可能比仅行号更有用。

有关set -e与其他人的问题,请参见例如这些:


meu*_*euh 15

Bash 有一个内置变量$LINENO,它在语句中被当前行号替换,所以你可以这样做

in_case_fail $? "at $LINENO: cp $file1 $file2"
Run Code Online (Sandbox Code Playgroud)

您还可以尝试trap ... ERR在命令失败时使用which running(如果未测试结果)。例如:

trap 'rc=$?; echo "error code $rc at $LINENO"; exit $rc' ERR
Run Code Online (Sandbox Code Playgroud)

然后,如果像这样的命令cp $file1 $file2失败,您将收到带有行号和退出的错误消息。您还会在变量中发现错误的命令$BASH_COMMAND(尽管没有任何重定向等)。