使用函数声明动态bash变量

时间:2016-07-28 18:07:02

标签: bash

我想在bash脚本中创建一个函数,声明一个变量和值提供给稍后要重用的函数。

function format_msg {
  declare "$1"="[ \033[00;32m$2 OK\033[0m ]"
}

format_msg "foo" "bar"
echo "${!foo}"

这是一个返回空值

4 个答案:

答案 0 :(得分:3)

declare builtin声明 local 变量(使用动态范围);所以当函数返回时变量就会消失。

如果你有一个足够新版的Bash,一个选项就是使用printf -v var选项(保存到变量而不是写入标准输出):

function format_msg {
  printf -v "$1" "%s" "[ \033[00;32m$2 OK\033[0m ]"
}

(也就是说,我同意CMPS的建议,你只需更改你的功能,使处理格式化,并让调用代码处理分配。一般的想法在Unix编程中,做一件事并做得很好"。)

编辑添加:我还应该指出代码中的其他两个问题,一旦解决上述问题就会遇到问题:

  • 除非您echo是专门定义的(例如,您已启用对反斜杠转义的支持),否则您似乎无法处理{{1}以便获得实际的颜色格式。所以我想你可能真的想要

    \033

    printf -v "$1" "[ \033[00;32m%s OK\033[0m ]" "$2" 处理printf

  • \033会将"${!foo}"内容解释为新的变量名,然后展开 的结果变量;我很确定你只想要

    $foo

答案 1 :(得分:1)

使用函数内部的声明使其成为函数的本地函数。

请改为尝试:

function format_msg {
  echo "[ \033[00;32m$1 OK\033[0m ]"
}

foo=$(format_msg "bar")
echo $foo

答案 2 :(得分:1)

默认情况下,

declare会创建一个局部变量。从bash 4.2开始,您可以使用-g选项来创建全局变量。

function format_msg {
  declare -g "$1=[ \033[00;32m$2 OK\033[0m ]"
}

答案 3 :(得分:0)

正如已经说过的那样,在这种特定情况下你的代码失败了,因为当使用declare时,bash会生成一个变量(好像命令一样)local(已经发出)。这相当于ksh的typeset,以及zsh的typeset,以及其替代形式declareintegerlocalreadonly(但不是export)。

此外,您正尝试通过间接形式echo "${!foo}"进行打印。这不会打印$foo的值,而是打印变量的值(如果存在),其名称是$foo的值。

如果使用此表单,则可以在函数内使用declare(对于bash 4.2 +):

declare -g "$1"="[ \033[00;32m$2 OK\033[0m ]"

对于较旧的bash版本(通常对于大多数shell)而不使用declare进行分配的最基本方法是始终令人担忧的eval(如果$1或{{1}的值有任何机会被攻击者(或外部用户)设置):

$2

当然,这会将字符串eval "$1"='"[ \033[00;32m'"$2"' OK\033[0m ]"' 分配给[ \033[00;32mbar OK\033[0m ],这似乎不是预期的目标。

这个简单的更改应该正确地将预期的转义字符分配给变量:

$foo

eval "$1"=$'"[ \033[00;32m'"$2"$' OK\033[0m ]"' 将更改为绿色,然后重置颜色设置。

为了消除评估的风险,我们需要使用其他东西。

对于ksh 93+和bash 4.3+,我们可以使用bar OK s(使用bash格式):

nameref

或者bash printf的-v选项:

declare -n ref=$1
ref=$'"[ \033[00;32m'"$2"$' OK\033[0m ]"'

在这种情况下,转义码(printf -v "$1" '"[ \033[00;32m%s OK\033[0m ]"' "$2" )的解释由printf完成。

一旦变量包含所需的值,最好使用printf打印而不是echo,并且不需要间接:

\033