如何在执行bash脚本时显示行号

127

我有一个测试脚本,其中包含许多命令并且会生成大量输出,我使用set -xset -vset -e,因此脚本在发生错误时会停止。但是,对于我来说仍然很难找到执行停止的哪一行以便定位问题。 是否有一种方法可以在每个命令执行之前输出脚本的行号? 或者在由set -x生成的命令展示之前输出行号? 或者任何可以解决我的脚本行位置问题的方法都将是一个很好的帮助。 谢谢。

6个回答

235

你提到你已经在使用 -x。变量PS4表示该值是在设置-x选项时打印在命令行之前的提示符,默认为冒号后跟空格:

您可以更改PS4以发出LINENO(当前正在执行的脚本或shell函数中的行号)。

例如,如果您的脚本读取:

$ cat script
foo=10
echo ${foo}
echo $((2 + 2))

这样执行会打印行号:

$ PS4='Line ${LINENO}: ' bash -x script
Line 1: foo=10
Line 2: echo 10
10
Line 3: echo 4
4

http://wiki.bash-hackers.org/scripting/debuggingtips 给出了最终的PS4命令,这个命令会输出您可能需要跟踪的所有内容:

export PS4='+(${BASH_SOURCE}:${LINENO}): ${FUNCNAME[0]:+${FUNCNAME[0]}(): }'

13
为什么没有人在“如何调试Shell脚本?”中提到这个?这比仅仅使用 echo 要好得多。 - Suvarna Pattayil
5
我不禁觉得-x应该打印行号,或者说-nx应该包括行号。对我来说,这是一个“什么鬼”的时刻... - jww
1
哎呀,我真希望早点知道那个PS4的配方……这会让我省去很多麻烦。 - niken
9
\033[0;33m+(${BASH_SOURCE}:${LINENO}):\033[0m ${FUNCNAME[0]:+${FUNCNAME[0]}(): }' 翻译为:一些颜色的\033[0;33m+(${BASH_SOURCE}:${LINENO}):\033[0m ${FUNCNAME[0]:+${FUNCNAME[0]}(): }' - Ulysse BN
1
如何在函数中使用它? - Munavir Chavody
显示剩余4条评论

50
在Bash中,$LINENO包含当前正在执行的脚本所在的行号。
如果你需要知道函数被调用的行号,请尝试使用$BASH_LINENO。请注意,此变量是一个数组。
例如:
#!/bin/bash       

function log() {
    echo "LINENO: ${LINENO}"
    echo "BASH_LINENO: ${BASH_LINENO[*]}"
}

function foo() {
    log "$@"
}

foo "$@"

有关Bash变量的详细信息,请在此处查看。


10

PS4的值为$LINENO,这是您所需的。

例如,以下脚本(myScript.sh):

       #!/bin/bash -xv
       PS4='${LINENO}: '
       echo "Hello"
       echo "World"

输出将是:

  ./myScript.sh
  +echo Hello
  3 : Hello
  +echo World
  4 : World

漂亮的解决方案! - Slaiyer

5

没有LINENO的shell的解决方法

在一个相当复杂的脚本中,我不想看到所有的行号;相反,我希望能够控制输出。

定义一个函数:

echo_line_no () {
    grep -n "$1" $0 |  sed "s/echo_line_no//" 
    # grep the line(s) containing input $1 with line numbers
    # replace the function name with nothing 
} # echo_line_no

像这样用引号包含起来

echo_line_no "this is a simple comment with a line number"

输出为

16   "this is a simple comment with a line number"

如果源文件中的这一行号是16。
这基本上回答了没有LINENO的ash或其他shell用户的如何在执行bash脚本时显示行号的问题。
还有什么需要补充的吗?
当然。你为什么需要这个?你如何使用它?你可以用它做什么?这种简单的方法真的足够或有用吗?你为什么要折腾这个?
想了解更多?阅读关于调试的反思

1

简单(但强大)的解决方案:在你认为引起问题的代码周围放置echo,并逐行移动echo直到屏幕上不再出现消息 - 因为脚本已经因错误而停止。

更加强大的解决方案:安装bashdb bash调试器,并逐行调试脚本。


2
在许多情况下,回显信息可能会有所帮助,但当您尝试将其应用于具有有意义、可解析输出的函数时,它就不够用了。 - Eliran Malka
1
@EliranMalka 说得好。在这种情况下,您可以将其回显到stderr:echo "foo" >&2 - hek2mgl
1
当目的是诊断性质的消息时,应在所有情况下将消息回显到stderr。 - Charles Duffy

1

如果您在函数中使用$LINENO,它将缓存第一次出现的行号。相反,请使用${BASH_LINENO[0]}


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接