多通道变量扩展,可能吗?

  • 本文关键字:变量 扩展 多通道 bash
  • 更新时间 :
  • 英文 :


如果你有一个包含其他变量的bash变量,是否可以"双倍"扩展它作为命令的一部分?

例如:

# Example #1
# ----------
# We define our first variable
TOP_LEVEL=/usr;
# Then use it (trivially) to set the values of other variables when executing a command
INC_DIRS="-I$TOP_LEVEL/include -I$TOP_LEVEL/local/include" 
LIB_DIRS="-L$TOP_LEVEL/lib -L$TOP_LEVEL/local/lib" 
./my_command

这是相当不言自明的。现在,让我们将此示例扩展到问题场景:

# Example #2
# ----------
# We define our first variable
TOP_LEVEL=/usr;
# Notice the use of single quotes below, to defer expansion of `TOP_LEVEL` to some point
# later - the time when DEFERRED_EVAL_INC_DIRS will actually be used
DEFERRED_EVAL_INC_DIRS='-I$TOP_LEVEL/include -I$TOP_LEVEL/local/include'
... # Other stuff happens here that may change the value of TOP_LEVEL, e.g.:
TOP_LEVEL=/usr/confused
# Since we used single quotes to define DEFERRED_EVAL_INC_DIRS, it is not affected
# Now we want to execute a command like before, and pass it three variables,
# INC_DIRS, LIB_DIRS, and FOO_LIB_INC_DIRS, in their fully expanded form:
INC_DIRS="-I$TOP_LEVEL/include -I$TOP_LEVEL/local/include" 
LIB_DIRS="-L$TOP_LEVEL/lib -L$TOP_LEVEL/local/lib" 
FOO_LIB_INC_DIRS="$DEFERRED_EVAL_INC_DIRS" ./my_command

INC_DIRSLIB_DIRS的扩展是微不足道的,它们变成了:

INC_DIRS='-I/usr/confused/include -I/usr/confused/local/include'
LIB_DIRS='-L/usr/confused/lib -I/usr/confused/local/lib'

有问题的扩展是FOO_LIB_INC_DIRS.所需的(完全展开的值应为):

FOO_LIB_INC_DIRS='-I/usr/confused/include -I/usr/confused/local/include'

...,最后将DEFERRED_EVAL_INC_DIRS值中使用的嵌入式$TOP_LEVEL变量扩展到它们的现值/usr/confused。因此,该变量需要第二个评估传递,并且其值中也需要保留空格,只是为了让生活更加困难。

如果DEFERRED_EVAL_INC_DIRS按名称引用单个变量(并且不包含其他字符),则可以使用${!DEFERRED_EVAL_INC_DIRS}间接变量引用构造。但是,这是一个更复杂的方案,周围有文本和需要扩展的变量的多种用途。

我尝试使用 bash 的eval,但无法在一个命令行中进行此扩展并且不引入其他变量,基本上是作为上述代码段的扩展。所需的全部扩展结果为:

INC_DIRS='-I/usr/confused/include -I/usr/confused/local/include' 
LIB_DIRS='-L/usr/confused/lib -I/usr/confused/local/lib' 
FOO_LIB_INC_DIRS='-I/usr/confused/include -I/usr/confused/local/include' 
./my_command

是否可以对示例 #2中的命令调用进行简单的更改或一组更改,以便进行完全扩展?

更新:这既不是类似问题的重复(至少以任何明显的方式),因为涉及更复杂的延迟扩展,同时保留跨空格的单词边界。如果解决方案对您来说很明显,请将其作为答案发布并更改为:

INC_DIRS="-I$TOP_LEVEL/include -I$TOP_LEVEL/local/include" 
LIB_DIRS="-L$TOP_LEVEL/lib -L$TOP_LEVEL/local/lib" 
FOO_LIB_INC_DIRS="$DEFERRED_EVAL_INC_DIRS" ./my_command

...,以完全扩展变量DEFERRED_EVAL_INC_DIRS,正确尊重单词边界,并产生:

INC_DIRS='-I/usr/confused/include -I/usr/confused/local/include' 
LIB_DIRS='-L/usr/confused/lib -I/usr/confused/local/lib' 
FOO_LIB_INC_DIRS='-I/usr/confused/include -I/usr/confused/local/include' 
./my_command

...,如果可能的话,最好不要创建子外壳(并且不要将此命令分解为多个命令或添加临时变量,这将使这种情况更简单)。

你可以在这里使用eval,但你需要在设置"较低级别"变量时调用它,例如尝试这个:

TOP_LEVEL="/usr"
eval "INC_DIRS='-I$TOP_LEVEL/include -I$TOP_LEVEL/local/include'"
echo TOP_LEVEL: $TOP_LEVEL
echo INC_DIRS: $INC_DIRS

当然,请注意使用评估的危险,例如在这里。

此外,如后续评论中所述,您还可以将"模板"视为要eval编辑的文件,例如尝试以下操作:

$ TOP_LEVEL="/usr"
$ cat template.sh 
INC_DIRS='-I$TOP_LEVEL/include -I$TOP_LEVEL/local/include'
$ eval $(<template.sh)
$ echo $INC_DIRS 
-I$TOP_LEVEL/include -I$TOP_LEVEL/local/include

最新更新