在bash中访问变量的函数定义时间,而不是评估时间

时间:2016-12-06 17:42:53

标签: bash shell

我希望我可以做这样的事情,输出就是“你好”

#!/bin/bash

foo="hello"

dummy() {
  local local_foo=`echo $foo`
  echo $local_foo
}

foo=''

dummy

这个问题意味着我希望在定义时捕获某些全局值的值,通常通过source blablabla.bash使用,并希望它定义一个捕获当前变量值的函数。

4 个答案:

答案 0 :(得分:4)

Sane Way

函数在运行时进行评估,而不是在定义时进行评估。由于您希望捕获在定义时存在的变量,因此您需要在此时分配一个单独的变量。

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

答案 1 :(得分:0)

好吧,您可以注释掉或删除foo=''行,这样就可以了。函数dummy在您调用它之前不会执行,这是在您清空了foo值之后,因此您可以回显一个空行。希望这会有所帮助。

答案 2 :(得分:0)

除非通过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

由于我不确定这是否解决了您的真正问题,只需:希望这会有所帮助。

答案 3 :(得分:0)

在受到@CharlesDuffy的启发之后,我认为使用eval可能会解决一些问题,并且示例可以修改如下:

#!/bin/bash

foo="hello"

eval "
dummy() {
  local local_foo=$foo
  echo \$local_foo
}
"

foo=''

dummy

哪会给你的结果'你好'而不是一无所获。

@CharlesDuffy指出这种解决方案非常危险:

  

local local_foo = $ foo是危险的错误:如果你的foo值包含   如$(rm -rf $ HOME)这样的扩展,它将被执行

使用eval可以提高性能,但安全性却很差。因此,我建议@CharlesDuffy给出答案。