In Bash, is there a way to expand variables twice in double quotes?

拥有回忆 提交于 2019-12-04 14:54:33

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.

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.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!