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


21

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

我用行号创建以下简单脚本,以解释我们需要什么。该脚本将从以下位置复制文件

cp $file1 $file2
cp $file3 $file4

cp命令之一失败时,该函数将退出并退出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


您可以使用set -x和/或set -v跟踪已执行的操作。并非完全符合您的要求,但也可能会有所帮助。
罗尔夫'18

Answers:


29

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

$ 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"

这可以通过捕获ERR,然后failure()使用当前执行的行号+ bash命令调用该函数来实现。

在这里,我没有采取任何照顾到创建的文件,f1f2f3,或f4。当我运行上面的脚本时:

$ ./yael.bash
cp: cannot stat f1’: No such file or directory
Failed at 17: cp -- "$file1" "$file2"

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


14

除了LINENO包含当前行号之外,还有BASH_LINENOand FUNCNAME(和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

运行将打印

'that thing' failed with exit code 123 in function 'foo' at line 9.

如果使用set -etrap ... ERR自动检测错误,请注意它们有一些警告。也很难包含脚本当时的执行情况的描述(就像您在示例中所做的那样),尽管对于普通用户而言,这可能不仅仅是行号而已。

例如,请参阅以下这些set -e与其他有关的问题:


13

Bash有一个内置变量$LINENO,在声明中会被当前行号替换,因此您可以执行

in_case_fail $? "at $LINENO: cp $file1 $file2"

您也可以尝试使用trap ... ERR命令失败时运行的命令(如果未测试结果)。例如:

trap 'rc=$?; echo "error code $rc at $LINENO"; exit $rc' ERR

然后,如果类似的命令cp $file1 $file2失败,您将得到错误消息,其中包含行号和退出。您还会在变量中找到错误的命令$BASH_COMMAND(尽管没有任何重定向等)。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.