问题
For debugging my scripts, I would like to add the internal variables $FUNCNAME and $LINENO at the beginning of each of my outputs, so I know what function and line number the output occurs on.
foo(){
local bar="something"
echo "$FUNCNAME $LINENO: I just set bar to $bar"
}
But since there will be many debugging outputs, it would be cleaner if I could do something like the following:
foo(){
local trace='$FUNCNAME $LINENO'
local bar="something"
echo "$trace: I just set bar to $bar"
}
But the above literally outputs: "$FUNCNAME $LINENO: I just set bar to something" I think it does this because double quotes only expands variables inside once.
Is there a syntactically clean way to expand variables twice in the same line?
回答1:
You cannot safely evaluate expansions twice when handling runtime data.
There are means to do re-evaluation, but they require trusting your data -- in the NSA system design sense of the word: "A trusted component is one that can break your system when it fails".
See BashFAQ #48 for a detailed discussion. Keep in mind that if you could be logging filenames, that any character except NUL can be present in a UNIX filename. $(rm -rf ~)'$(rm -rf ~)'.txt
is a legal name. *
is a legal name.
Consider a different approach:
#!/usr/bin/env bash
trace() { echo "${FUNCNAME[1]}:${BASH_LINENO[0]}: $*" >&2; }
foo() {
bar=baz
trace "I just set bar to $bar"
}
foo
...which, when run with bash 4.4.19(1)-release, emits:
foo:7: I just set bar to baz
Note the use of ${BASH_LINENO[0]}
and ${FUNCNAME[1]}
; this is because BASH_LINENO
is defined as follows:
An array variable whose members are the line numbers in source files where each corresponding member of FUNCNAME was invoked.
Thus, FUNCNAME[0]
is trace
, whereas FUNCNAME[1]
is foo
; whereas BASH_LINENO[0]
is the line from which trace
was called -- a line which is inside the function foo
.
回答2:
Although eval
has its dangers, getting a second expansion is what it does:
foo(){
local trace='$FUNCNAME $LINENO'
local bar="something"
eval echo "$trace: I just set bar to $bar"
}
foo
Gives:
foo 6: I just set bar to something
Just be careful not to eval
anything that has come from external sources, since you could get a command injected into the string.
来源:https://stackoverflow.com/questions/50537090/in-bash-is-there-a-way-to-expand-variables-twice-in-double-quotes