bash - 如何在 bash 脚本中打印所有函数调用命令
问题描述
有没有办法在 bash 脚本中打印所有函数调用顺序,就像 IDEA Intellij 中的调用层次结构?
提前致谢。
解决方案
有一些预定义的 Bash 变量会在运行时公开其中的一些信息,但是如果您想要一个静态确定的调用层次结构,我不知道有任何工具可以为 Bash 做到这一点。
FUNCNAME
以下是使用预定义数组和BASH_LINENO
(文档)从脚本本身中找到它的方法BASH_SOURCE
:
调用者.sh
#!/usr/bin/env bash
print_callers() {
local func file line
echo 'CALLERS:'
for i in "${!FUNCNAME[@]}"; do
# Uncomment next line to skip the current function, i.e., `print_callers`.
# if [[ $i == 0 ]]; then continue; fi
func=${FUNCNAME[$i]}
file=${BASH_SOURCE[$i]}
line=${BASH_LINENO[$i - 1]}
echo " - $func ($file:$line)"
done
echo
} >&2
baz() {
print_callers
echo 'this is a leaf function'
}
bar() {
baz
}
foo() {
bar
}
foo
以上将输出:
$ ./callers.sh
CALLERS:
- print_callers (./callers.sh:0)
- baz (./callers.sh:21)
- bar (./callers.sh:26)
- foo (./callers.sh:30)
- main (./callers.sh:33)
this is a leaf function
我实际上是结合使用这种方法,trap
以便在抛出错误时打印脚本执行的堆栈跟踪。我有这个prelude.sh
文件,可以在不同的 Bash 脚本中重复使用:
前奏曲.sh
#!/usr/bin/env bash
shopt -so errexit
shopt -so errtrace
shopt -so noglob
shopt -so nounset
shopt -so pipefail
shopt -s extglob
bold() {
tput bold; echo -n "$@"; tput sgr0
}
trap ERR ERR; ERR() {
local code=$?
local cmnd=$BASH_COMMAND
local func file line level
echo "Exit status $(bold "$code") for command: $(bold "$cmnd")"
for i in "${!FUNCNAME[@]}"; do
if [[ $i == 0 ]]; then continue; fi
func=${FUNCNAME[$i]}
file=${BASH_SOURCE[$i]}
line=${BASH_LINENO[$i - 1]}
if (( i == ${#FUNCNAME[@]} - 1 )); then
level='└─'
func="<$func>"
else
level='├─'
fi
echo " $level $(bold "$func") ($file:$line)"
done
exit 1
} >&2
然后我可以在我的其他脚本中像这样使用它(prelude.sh
is on PATH
):
失败.sh
#!/usr/bin/env bash
source prelude.sh
foo() {
echo '' | grep 'nope'
}
foo
以上将导致这个堆栈跟踪被打印出来:
Exit status 1 for command: grep 'nope'
├─ foo (./fails.sh:6)
└─ <main> (./fails.sh:9)
推荐阅读
- docker - docker ERR_CONNECTION_REFUSED 内的 Chrome
- javascript - 使用 Context API 在非嵌套组件之间传递变量
- python - 使用 selenium 和 python 从 iframe 中获取文本
- python - 用 Python 覆盖 Excel 中的工作表
- r - 从 R 中的两个表中查找不重叠的值
- excel - 如何复制和粘贴范围而不是行?
- python - 在应用之前从 kv 文件中获取子级
- powershell - 在 PowerShell 中的子属性上使用 Where-Object 过滤(xml-)数据
- awk - sed / awk - 删除有条件的换行符
- r - 有条件地合并来自两个数据帧的数据