【问题标题】:Replacing environment variables in a properties file替换属性文件中的环境变量
【发布时间】:2011-07-13 13:25:57
【问题描述】:

在 Linux 中,假设我有以下文件(例如 conf.properties):

HOST_URL=http://$HOSTNAME
STD_CONFIG=http://$HOSTNAME/config
USER_CONFIG=http://$HOSTNAME/config/$unconfigured

我想创建另一个替换所有环境变量的文件...例如假设环境变量 $HOSTNAME 是 'myhost' 并且 $unconfigured 没有设置,脚本应该产生以下输出:

HOST_URL=http://myhost
STD_CONFIG=http://myhost/config
USER_CONFIG=http://myhost/config/

我认为这可以通过某种 sed/awk 魔法在一个简单的单行中完成,但我不是专家,我的搜索一直在脉络中,所以感谢任何帮助。

编辑:

我应该提到该文件实际上可以是任何格式的文本文件,例如 xml。我只想用当前在环境中设置的任何内容替换任何看起来像 env 变量的内容。

【问题讨论】:

  • 你应该考虑接受正确的答案

标签: linux


【解决方案1】:

这就是envsubst 的用途。

echo 'Hello $USER'
Hello $USER
echo 'Hello $USER' | envsubst
Hello malvineous

不过,您可能会更像这样使用它:

envsubst < input.txt > output.txt

envsubst 似乎是 GNU gettext 的一部分。

【讨论】:

  • 这似乎是这里唯一真正正确的答案。应该标得更高。
  • 我只想对这个答案表示感谢。我和我的朋友在 sed、awk 和其他“技巧”上苦苦挣扎,这个答案救了我们。知识就是力量。谢谢!
【解决方案2】:
sed 's/$HOSTNAME/myhost/g;s/$unconfigured//g' yourfile.txt > another_file.txt

更新:

根据您问题中的更新,这不是一个好的解决方案。

更新2:

这是基于answer to a related question。我已经破解了它(我不熟悉 perl)来删除未定义的变量。

perl -p -e 's/\$\{([^}]+)\}/defined $ENV{$1} ? $ENV{$1} : $&/eg; s/\$\{([^}]+)\}//eg' yourfile.txt

应该适用于任何输入文本文件,但是您需要使用简化字符串匹配的${...} 格式定义变量。

关于 eval 邪恶的咆哮已移至separate post,以免混淆读者

【讨论】:

  • 或更具可读性(恕我直言):sed -e 's/$HOSTNAME/myhost/' -e 's/$unconfigured// ...
  • 假设我知道配置文件中使用的环境变量,我可以使用这种技术,但我真的想要更通用的东西。
  • @Shawn-Chin 谢谢!我可能会使用它,因为我喜欢 ${} 使用属性的风格。
  • 我认为 perl 命令可以根据相关问题的 cmets 简化为 perl -p -e 's/\$\{([^}]+)\}/defined $ENV{$1} ? $ENV{$1} : ""/eg' yourfile.txt,而不是使用第二个正则表达式来删除空变量。您只需将$&amp; 替换为""
  • @JoelPearson 的正则表达式的优点是不删除反斜杠
【解决方案3】:

“评价是邪恶的”

这不是答案,而是对using eval for this task 的回应。你真的真的不想那样做。

图表1:恶意模板文件:

HOST_URL=http://$HOSTNAME
STD_CONFIG=http://$HOSTNAME/config
USER_CONFIG=http://$HOSTNAME/config/$unconfigured
&& cat /etc/redhat-release

毫无戒心的用户:

[lsc@aphek]$ cat somefile | while read line; do echo $(eval echo `echo $line`); done
HOST_URL=http://xyz
STD_CONFIG=http://xyz/config
USER_CONFIG=http://xyz/config/
Red Hat Enterprise Linux WS release 4 (Nahant Update 9)

注意最后一行!

现在,想象一下可能性......

【讨论】:

  • 我也想到了这个。我很惊讶人们这么认为。 bash 中应该有替代机制,真的!否则,我们应该为此编写一个标准工具。
【解决方案4】:

我会这样做:

# Set the $HOSTNAME and other variables
# Now evaluate the properties file as a shell script.
. config.properties
# Write the values
cat >somefile <<EOF
HOST_URL=$HOST_URL
STD_CONFIG=$STD_CONFIG
USER_CONFIG=$USER_CONFIG
EOF

编辑:或者这个非常讨厌的事情(我相信有更好的方法)

for name in HOST_URL STD_CONFIG USER_CONFIG
    echo "$name=$(eval echo `echo '$'$name`)" >>somefile
end

【讨论】:

  • 我不能假设该文件是一个有效的 shell 脚本(只是 name=value) - 它可能是任何格式,例如 xml。
  • @Andy Whitfield:太糟糕了 :-) 然后你就去 awk/sed。
  • 你的编辑给了我一个想法:这个小金块:cat somefile | while read line; do echo $(eval echo echo $line); done
  • 这里的评论中的格式不太好,所以我将其粘贴为参考答案。
【解决方案5】:

感谢@DarkDust,我想出了这个:

cat somefile | while read line; do echo $(eval echo `echo $line`); done > somefile.replaced

【讨论】:

  • 甚至是单线 ;-) 现在这看起来像是一个解决方案,只要您知道您的输入文件除了变量之外不会有 $
  • 请不要使用它。请原谅提高的声音,但这是需要尖叫的一种情况。请参阅我的回答中的说明。
  • @Shawn 没有问题 - 感谢您的警告。我将使用 perl 行 - 就像一个魅力。
  • 我更担心未来可能会遇到它的毫无戒心的用户。将警告作为单独的项目发布,以免引起混淆。
  • 这将省略行首的空格以及包含#的行。
【解决方案6】:

我用这个 oneliner 替换了文件中的${VARIABLE} 样式变量:

TARGET_FILE=/etc/apache2/apache2.conf; for VARNAME in $(grep -P -o -e '\$\{\S+\}' ${TARGET_FILE} | sed -e 's|^\${||g' -e 's|}$||g' | sort -u); do sed -i "s|\${$(echo $VARNAME)}|${!VARNAME}|g" ${TARGET_FILE}; done

我很确定有人可以使用 awk 以 1/3 的长度完成此操作……感觉挑战! ;)

【讨论】:

    【解决方案7】:

    这是我喜欢用来解决这个确切问题的 Javascript 的 sn-p:

    // A Javascript version of envsubst for our builds
    // Purpose: replace all ocurrences of ${VAR} with the equivalent var from the environment from stdin
    var readline = require('readline');
    
    var rl = readline.createInterface({
      input: process.stdin,
      output: process.stdout,
      terminal: false
    });
    
    const environment = process.env;
    
    rl.on('line', function(line) {
      const newLine = line.replace(/\$\{([a-zA-Z0-9_]+)\}/g, function(_match, variable) {
        const envVar = environment[variable];
        return envVar ? envVar : '';
      });
    
      process.stdout.write(`${newLine}\n`);
    });
    

    希望这对其他人有所帮助。

    【讨论】:

      【解决方案8】:

      这是一个简短的单行代码,它使用 python 的花括号格式来安全地执行魔法:

      contents=\"\"\"`cat $file`\"\"\"; python -c "import os;print $contents.format(**os.environ)"
      
      • 避免邪恶评估
      • 允许输出花括号:使用{{ 而不是{
      • 调用脚本时无需显式指定变量

      例如,给定属性文件settings.properties

      # my properties file
      someVar = {MY_ENV_VAR}
      curlyBraceVar = has {{curly braces}}
      

      然后,替换为:

      $ export MY_ENV_VAR="hello"
      $ file=settings.properties 
      $ contents=\"\"\"`cat $file`\"\"\"; python  -c "import os;print $contents.format(**os.environ)"
      # my properties file
      someVar = hello
      curlyBraceVar = has {curly braces}
      

      这里有一个脚本:https://raw.githubusercontent.com/aneilbaboo/machome/master/bin/substenv

      【讨论】:

      • 这并不能避免邪恶的评估,它只是混淆了它。 echo '"""; print "arbitrary code execution"; """' &gt; ~/myfile; 创建一个文件,该文件会导致对一些任意代码进行评估。
      【解决方案9】:

      如果你已经安装了nodejs,你可以运行

      npx @utft/tt -e FOO=bar /path/to/input /path/to/output
      

      或者您可以通过编程方式运行它 https://github.com/utftufutukgyftryidytftuv/tt

      【讨论】:

        猜你喜欢
        • 2019-03-10
        • 1970-01-01
        • 2018-03-22
        • 2021-08-01
        • 2016-02-02
        • 1970-01-01
        • 2017-12-14
        • 2015-11-26
        • 1970-01-01
        相关资源
        最近更新 更多