在 bash 中,我可以这样写:
caller 0
并收到呼叫者上下文的:
- 电话号码
- 功能
- 脚本名称
这对于调试非常有用。鉴于:
yelp () { caller 0; }
然后我可以写信yelp
查看正在到达哪些代码行。
我可以实施caller 0
为bash
:
echo "${BASH_LINENO[0]} ${FUNCNAME[1]} ${BASH_SOURCE[1]"
caller 0
我怎样才能得到与中相同的输出zsh
?
答案1
我不认为有内置的命令等价的,但是这四个变量的某种组合zsh/参数模块可以使用:
funcfiletrace
EVAL_LINENO
该数组包含调用当前函数、源文件或(如果已设置)命令的位置的绝对行号和相应的文件名eval
。该数组与funcsourcetrace
和具有相同的长度functrace
,但不同之处funcsourcetrace
在于行和文件是调用点,而不是定义点,并且不同之处在于functrace
所有值都是文件中的绝对行号,而不是相对于函数的开始(如果有)。funcsourcetrace
此数组包含定义当前正在执行的函数、源文件和(如果
EVAL_LINENO
设置了)命令的点的文件名和行号。行号是“ ”或“ ”开始的行。对于自动加载的函数,行号报告为零。每个元素的格式为。eval
function name
name ()
filename:lineno
对于从本机 zsh 格式的文件自动加载的函数(其中仅函数主体出现在文件中),或者对于已由
source
或 '.
' 内置函数执行的文件,跟踪信息显示为filename:0
,因为整个文件是定义。加载函数时,源文件名将解析为绝对路径,否则将解析其路径。大多数用户会对数组中的信息感兴趣
funcfiletrace
。funcstack
该数组包含函数的名称、源文件和(如果
EVAL_LINENO
已设置)eval
命令。目前正在执行。第一个元素是使用该参数的函数的名称。标准 shell 数组
zsh_eval_context
可用于确定在每个深度执行的 shell 构造的类型:但是请注意,顺序相反,最后一项是最新的项,并且更详细,例如包括一个条目toplevel,主要的 shell 代码以交互方式或从脚本执行,这在$funcstack
.functrace
该数组包含与当前正在执行的函数相对应的调用者的名称和行号。每个元素的格式为
name:lineno
.还会显示源文件的调用者;调用者是执行source
or ' ' 命令的点。.
比较:
foo.bash
:
#! /bin/bash
yelp() {
caller 0
}
foo () {
yelp
}
foo
foo.zsh
:
#! /bin/zsh
yelp() {
print -l -- $funcfiletrace - $funcsourcetrace - $funcstack - $functrace
}
foo () {
yelp
}
foo
结果:
$ bash foo.bash
7 foo foo.bash
$ zsh foo.zsh
foo.zsh:7
foo.zsh:10
-
foo.zsh:2
foo.zsh:6
-
yelp
foo
-
foo:1
foo.zsh:10
因此,相应的值在${funcfiletrace[1]}
和中${funcstack[-1]}
。修改yelp
为:
yelp() {
print -- $funcfiletrace[1] $funcstack[-1]
}
输出是:
foo.zsh:7 foo
这与 bash 非常接近
7 foo foo.bash
答案2
基于穆鲁的回答,我实现了以下功能,该功能适用于两者{ba,z}sh
:
$ cat yelp
#!/bin/zsh
# Say the file, line number and optional message for debugging
# Inspired by bash's `caller` builtin
# Thanks to https://unix.stackexchange.com/a/453153/143394
function yelp () {
# shellcheck disable=SC2154 # undeclared zsh variables in bash
if [[ $BASH_VERSION ]]; then
local file=${BASH_SOURCE[1]} func=${FUNCNAME[1]} line=${BASH_LINENO[0]}
else # zsh
emulate -L zsh # because we may be sourced by zsh `emulate bash -c`
# $funcfiletrace has format: file:line
local file=${funcfiletrace[1]%:*} line=${funcfiletrace[1]##*:}
local func=${funcstack[2]}
[[ $func =~ / ]] && func=source # $func may be filename. Use bash behaviour
fi
echo "${file##*/}:$func:$line $*" > /dev/tty
}
foo () { yelp; }
yelp
foo
输出是:
$ ./yelp
yelp::20
yelp:foo:19