为了调试我的脚本,我想在每个输出的开头添加内部变量$ FUNCNAME和$ LINENO,所以我知道输出发生的函数和行号。
foo(){
local bar="something"
echo "$FUNCNAME $LINENO: I just set bar to $bar"
}
但是因为会有很多调试输出,所以如果我可以执行以下操作会更清晰:
foo(){
local trace='$FUNCNAME $LINENO'
local bar="something"
echo "$trace: I just set bar to $bar"
}
但以上字面输出: " $ FUNCNAME $ LINENO:我只是设置了一些东西" 我认为这样做是因为双引号只会在一次内部扩展变量。
在同一行中有两种语法清晰的方法来扩展变量吗?
答案 0 :(得分:7)
有办法进行重新评估,但它们需要信任您的数据 - 在NSA系统设计意义上的一句话:"可信组件是一个可以在系统失败时破坏您的系统的组件。
有关详细讨论,请参阅BashFAQ #48。请记住,如果您可以记录文件名,那么除了NUL 之外的任何字符都可以出现在UNIX文件名中。 $(rm -rf ~)'$(rm -rf ~)'.txt
是合法的名称。 *
是合法的名称。
#!/usr/bin/env bash
trace() { echo "${FUNCNAME[1]}:${BASH_LINENO[0]}: $*" >&2; }
foo() {
bar=baz
trace "I just set bar to $bar"
}
foo
...当使用bash 4.4.19(1)运行时,发布:
foo:7: I just set bar to baz
请注意使用${BASH_LINENO[0]}
和${FUNCNAME[1]}
;这是因为BASH_LINENO
定义如下:
一个数组变量,其成员是源文件中的行号,其中调用了FUNCNAME的每个相应成员。
因此,FUNCNAME[0]
为trace
,而FUNCNAME[1]
为foo
;而BASH_LINENO[0]
是trace
被调用的行 - 一行在函数foo
内。
答案 1 :(得分:1)
虽然eval
有危险,但第二次扩展就是它的作用:
foo(){
local trace='$FUNCNAME $LINENO'
local bar="something"
eval echo "$trace: I just set bar to $bar"
}
foo
给出:
foo 6: I just set bar to something
请注意不要eval
任何来自外部来源的内容,因为你可以将一个命令注入到字符串中。
答案 2 :(得分:0)
是以扩大两倍;但否,它不会满足您的期望。
是,bash提供了一种对变量进行“双重扩展”的方法,也就是一种首先解释变量,然后将其用作其他变量的名称的方法,其中另一个变量是实际要扩展的内容。这称为“间接”。通过“间接”,bash允许shell变量引用另一个shell变量,最终值来自引用的变量。因此,可以通过引用传递bash变量。
语法只是普通的花括号样式扩展,但是名称前带有感叹号。
${!VARNAME}
它的用法如下:
BAR="my final value";
FOO=BAR
echo ${!FOO};
...产生此输出...
my final value
否,您不能使用此机制与$(eval“ echo $ VAR1 $ VAR2”)相同。第一次解释的结果必须与shell变量的名称完全相同。它不接受字符串,并且不理解美元符号。所以这行不通:
BAR="my final value";
FOO='$BAR'; # The dollar sign confuses things
echo ${!FOO}; # Fails because there is no variable named '$BAR'
因此,它不会解决您的最终任务。但是,间接可以是一个强大的工具。