【问题标题】:Bash Script Properties File Using '.' in Variable Name使用“.”的 Bash 脚本属性文件在变量名中
【发布时间】:2014-03-02 17:32:27
【问题描述】:

我是 bash 脚本的新手,并且有一个关于在 bash 脚本中使用 .properties 文件中的属性的问题。

我见过一个使用'.'的 bash 属性文件。变量名之间,例如:

this.prop.one=someProperty

而且我已经看到它们是从如下脚本中调用的:

echo ${this.prop.one}

但是当我尝试设置这个属性时,我得到一个错误:

./test.sh: line 5: ${this.prop.one}: bad substitution

如果我不使用'.',我可以使用属性。在变量名中,并包含 props 文件:

#!/bin/bash
. test.properties
echo ${this_prop_one}

我真的很想能够使用 '.'在变量名中,并且,如果可能的话,不必包含 。 test.properties 在脚本中。

这可能吗?

更新:

感谢您的回答!那么,这很奇怪。我正在使用一个看起来像这样的 bash 脚本(glassfish 的服务):

#!/bin/bash

start() {
        sudo ${glassfish.home.dir}/bin/asadmin start-domain domain1
}

...

...还有像这样的属性文件(build.properties):

# glassfish
glassfish.version=2.1
glassfish.home.dir=${app.install.dir}/${glassfish.target}
...

那么,一定有某种方法可以做到这一点吗?如果它们在属性文件中声明,它们是否可能不被定义为“变量”?再次感谢。

【问题讨论】:

  • @DigitalTrauma ...如果仅将其读取为引用环境变量,则这是重复的。如果目标只是能够使用这些变量(这就是我阅读问题的方式),还有其他方法可以存储它们起作用。
  • @CharlesDuffy - 是的,这是解决这个问题的好方法 - 近距离投票被撤回。
  • @MattB,不,您现有的使用${glassfish.home.dir} 的脚本不是而且从来都不是有效的bash。我敢说它是别的东西——比如通过 Java 程序运行以创建 bash 脚本的模板。
  • @MattB ...顺便说一句,我试过用谷歌搜索你提供的代码,我唯一找到sudo ${glassfish.home.dir}/bin/asadmin的地方就是这个问题本身。指向您找到它的位置的指针,以便分析上下文,会很有帮助。

标签: linux bash scripting properties-file


【解决方案1】:

没有办法。 bash 手册中关于变量名的说明如下:

名字

仅由字母、数字和下划线组成并以字母或下划线开头的单词。名称用作 shell 变量和函数名称。也称为标识符。

不允许点。

【讨论】:

  • 你可以cat文件,通过sed(用_替换.)和eval结果 - 如果你相信它的内容。
  • 类似于 eval $( cat file.properties | sed y/./_/ ) 的东西 - 只需确保 eval 不在子 shell 中执行(例如,不要将任何东西输入其中)
  • @JohannesH.,从安全角度来看,这相当可怕;属性文件应该包含数据,但是通过评估它们,您将它们视为代码。
  • @CharlesDuffy 我知道。这是一个非常快速和肮脏的解决方案,只有在格式正确的情况下才有效(也就是说,= 前后没有空格,由" 包围的值),并且如我的建议所述,您信任其中的所有内容.当然,这根本不是通用解决方案
  • 没错,但 OP 也想避免这种情况;)
【解决方案2】:

dot 不允许作为变量名。所以你不能只是简单地获取属性文件。

你可以做的是:

“解析”文件,而不是源文件。例如。使用 perl、awk 或 grep 获取感兴趣的属性名称的值,并将其分配给您的 shell var。

如果您确实想设置名称中带有点的 var,您可以使用 env 'a.b.c=xyz' 并从 env 输出中获取 a.b.c

【讨论】:

  • 并非所有 shell 都支持这一点——某些版本的 bash 实际上会删除任何不是有效 shell 变量的环境变量。
【解决方案3】:

将它们加载到关联数组中。这将要求您的 shell 是 bash 4.x,而不是 /bin/sh(即使是 bash 的符号链接,它也以 POSIX 兼容模式运行)。

declare -A props
while read -r; do
  [[ $REPLY = *=* ]] || continue
  props[${REPLY%%=*}]=${REPLY#*=}
done <input-file.properties

...之后您可以像这样访问它们:

echo "${props[this.prop.name]}"

如果你想递归查找引用,那么它会变得更有趣。

getProp__property_re='[$][{]([[:alnum:].]+)[}]'
getProp() {
  declare -A seen=( ) # to prevent endless recursion
  declare propName=$1
  declare value=${props[$propName]}
  while [[ $value =~ $getProp__property_re ]]; do
    nestedProp=${BASH_REMATCH[1]}
    if [[ ${seen[$nestedProp]} ]]; then
      echo "ERROR: Recursive definition encountered looking up $propName" >&2
      return 1
    fi
    value=${value//${BASH_REMATCH[0]}/${props[$nestedProp]}}
  done
  printf '%s\n' "$value"
}

如果我们将props 定义如下(您也可以通过在此答案顶部使用适当的input-file.properties 运行循环来获得):

declare -A props=(
  [glassfish.home.dir]='${app.install.dir}/${glassfish.target}'
  [app.install.dir]=/install
  [glassfish.target]=target
)

...那么行为如下:

bash4-4.4$ getProp glassfish.home.dir
/install/target

【讨论】:

  • 绝妙的答案!它完全解决了我的问题。使用显式方式处理 bash 解释器的提示是解决方案的重要组成部分!谢谢!
猜你喜欢
  • 2019-09-19
  • 2015-11-13
  • 2016-06-27
  • 2021-11-04
  • 1970-01-01
  • 1970-01-01
  • 2021-08-23
  • 1970-01-01
相关资源
最近更新 更多