访问bash中变量的函数定义时间(而不是计算时间)值
我希望我能做这样的事情,结果会是“你好”访问bash中变量的函数定义时间(而不是计算时间)值,bash,shell,Bash,Shell,我希望我能做这样的事情,结果会是“你好” 这个问题意味着我想在定义时捕获一些全局值的值,通常通过source blabla.bash使用,并希望它定义一个捕获当前变量值的函数。 函数在运行时进行计算,而不是在定义时进行计算。由于您希望捕获定义时存在的变量,因此需要在定义时分配一个单独的变量 foo="hello" # By convention, global variables prefixed by a function name and double underscore are fo
这个问题意味着我想在定义时捕获一些全局值的值,通常通过
source blabla.bash
使用,并希望它定义一个捕获当前变量值的函数。
函数在运行时进行计算,而不是在定义时进行计算。由于您希望捕获定义时存在的变量,因此需要在定义时分配一个单独的变量
foo="hello"
# By convention, global variables prefixed by a function name and double underscore are for
# the exclusive use of that function.
readonly dummy__foo="$foo" # capture foo as of dummy definition time, and prevent changes
dummy() {
local local_foo=$dummy__foo # ...and refer to that captured copy
echo "$local_foo"
}
foo=""
dummy
疯狂的方式 但是,如果您愿意犯下危害人类罪,则可以通过生成代码来获取价值。例如:
# usage: with_locals functionname k1=v1 [k2=v2 [...]]
with_locals() {
local func_name func_text assignments
func_name=$1; shift || return ## fail if out of arguments
(( $# )) || return ## noop if not given at least one assignment
func_text=$(declare -f "$func_name")
for arg; do
if [[ $arg = *=* ]]; then ## if we already look like an assignment, leave be
printf -v arg_q 'local %q; ' "$arg"
else ## otherwise, assume we're a bare name and run a lookup
printf -v arg_q 'local %q=%q; ' "$arg" "${!arg}"
fi
assignments+="$arg_q"
done
# suffix first instance of { in the function definition with our assignments
eval "${func_text/{/{ $assignments}"
}
……此后:
foo=hello
dummy() {
local local_foo="$foo"
echo "$local_foo"
}
with_locals dummy foo ## redefine dummy to always use the current value of "foo"
foo=''
dummy
好的,您可以注释掉或删除
foo='
行,这样就可以了。函数dummy
在您调用它之前不会执行,这是在您清除了foo
值之后执行的,因此您可以得到一个空行。希望这有帮助。除非bash调用函数,否则无法在函数内执行代码。只有另一种方法可以调用其他函数,用于定义要调用的函数。这就是动态函数定义 我不相信你想要那样 另一种方法是存储foo的值(调用函数),然后在值更改后再次调用它。像这样的东西:
#!/bin/bash
foo="hello"
dummy() {
${global_foo+false} &&
global_foo="$foo" ||
echo "old_foo=$global_foo new_foo=$foo"
}
dummy
foo='new'
dummy
foo="a whole new foo"
dummy
调用它将打印:
$ ./script
old_foo=hello new_foo=new
old_foo=hello new_foo=a whole new foo
由于我不确定这是否能解决您真正的问题,我只想:希望这能有所帮助。受@CharlesDuffy的启发,我认为使用eval可能会解决一些问题,示例可以修改如下:
#!/bin/bash
foo="hello"
eval "
dummy() {
local local_foo=$foo
echo \$local_foo
}
"
foo=''
dummy
这将给出结果“hello”而不是“nothing”
@CharlesDuffy指出,这种解决方案相当危险: local\u foo=$foo存在危险的错误:如果您的foo值包含 一个扩展,例如$(rm-rf$HOME),它将被执行
使用eval在性能上是好的,但是在安全性上是坏的。因此,我建议@CharlesDuffy给出答案。因为在调用伪函数之前,您有意这样做
foo='
,所以您几乎不能这样做。此外,通常您会使用local\u foo=“$foo”
而不是echo
来调用和捕获结果。如果您是bash新手,我建议您……那么您希望在函数定义时捕获变量的值,而不是在求值时?考虑编辑你的问题,具体地说,这就是你想要的(而且,不,你不能做它而不创建一个单独的变量)…嗯,创建一个单独的变量,或者做一些非常糟糕的事情(动态地生成你的函数)。BTW,你的真正目标是什么?比如说,希望您不打算通过从局部变量集中清除密码来向用户隐藏密码——考虑到访问函数的原始文本是多么微不足道,这样的行为实际上是没有用的。很难相信这告诉OP他们不知道的任何事情——如果不是为了说明他们打算使用定义dummy
时存在的值,他们为什么要把foo=''
放在那里,vs运行dummy
时存在的值?使用local\ucode>前缀命名全局变量有点误导,不是吗?(如果OP想要将内容复制到另一个全局变量,我认为有一些方法比第一次调用函数的行为与在同一个shell或其子shell中的未来调用的行为完全不同更令人惊讶。)@charlesduff当然,让我来说明一下全局变量。是的,这就是为什么我从一开始就称这个解决方案为“hackish”。您可以修改它以使其更安全:如果您运行printf-v foo_q“%q'$foo”
,然后在eval
中使用$foo_q
,那么它就不会像前面所描述的那样被利用。在生成要eval
的文本时,也可以使用$(printf'%q'$foo')
,但这会导致性能下降,因为它会创建一个子shell,除非您的解释器(如ksh93)足够聪明,能够对其进行优化。(当然,我自己的答案也会支付一次子shell惩罚,以捕获declare-f
的输出——我想这就是你在谈论手写eval
时所指的更快;在现代unixlikes上,子shell相对便宜,但肯定有bash运行的平台——比如Cygwin——wh在它们更贵之前)。
#!/bin/bash
foo="hello"
eval "
dummy() {
local local_foo=$foo
echo \$local_foo
}
"
foo=''
dummy