在bash中间接引用,为什么这不起作用?

时间:2014-03-04 11:46:55

标签: bash function

我正在尝试通过使用函数来整理我的一个bash脚本。该脚本从config.ini文件中设置许多变量,然后列出它们并要求确认用户希望继续使用这些预定义值。如果没有,它会逐步执行每个变量并要求输入一个新变量(或将其留空并按Enter键以使用预定义值)。这段代码实现了:

echo Current output folder: $OUTPUT_FOLDER
echo -n "Enter new output folder: "
read C_OUTPUT_FOLDER
if [ -n "$C_OUTPUT_FOLDER" ]; then OUTPUT_FOLDER=$C_OUTPUT_FOLDER; fi

我们的想法是将$OUTPUT_FOLDER设置为$C_OUTPUT_FOLDER的值,但前提是$C_OUTPUT_FOLDER不为空。如果$C_OUTPUT_FOLDER为空,则它将不执行任何操作,并保留$OUTPUT_FOLDER,以便稍后在脚本中使用。

config.ini中设置了6个变量,因此该块当前重复了6次。我已经创建了一个函数new_config (),如下所示:

new_config () {
  echo Current $1: ${!2}
  echo -n "Enter new $1: "
  read $3
  if [ -n "${!3}" ]; then $2=${!3}; fi
}

我正在调用它(在这个例子中):

new_config "output folder" OUTPUT_FOLDER C_OUTPUT_FOLDER

当我运行脚本时,它在if行上有错误:

./test.sh: line 9: OUTPUT_FOLDER=blah: command not found

那么,是什么给出的?脚本中的代码块运行良好(在我非常新的眼中),函数应该完全相同。

提前感谢任何指示。

1 个答案:

答案 0 :(得分:0)

问题是bash在变量替换之前将命令拆分为标记,请参阅http://tldp.org/LDP/Bash-Beginners-Guide/html/sect_01_04.html#sect_01_04_01_01。具体来说,POSIX shell的规则使赋值成为标记化的特殊情况:"If all the characters preceding '=' form a valid name (see XBD Name), the token ASSIGNMENT_WORD shall be returned." - 它是触发赋值路径的ASSIGNMENT_WORD标记。它不会在变量替换后重复标记化,这就是您的代码不起作用的原因。

您可以让代码像这样工作:

new_config () {
  echo Current $1: ${!2}
  echo -n "Enter new $1: "
  read $3
  if [[ -n "${!3}" ]]; then echo setting "$2='${!3}'"; eval "$2='${!3}'"; fi
}

new_config "output folder" OUTPUT_FOLDER C_OUTPUT_FOLDER
echo $OUTPUT_FOLDER

正如@chepner指出的那样,你可以在这里使用declare -g $2="${!3}"而不是eval,在更新的bash版本上使用更好的答案。不幸的是declare -g需要bash 4.2,即使它已经3年了,它仍然不是无处不在 - 例如,OS X Mavericks仍然停留在3.2.51。