Linux 替换属性文件中的环境变量

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/5274343/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-05 03:12:49  来源:igfitidea点击:

Replacing environment variables in a properties file

linux

提问by Andy Whitfield

In Linux, say I have the following file (e.g. conf.properties):

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

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

I want to create another file with all the environment variables replaced...e.g. say the environment variable $HOSTNAME is 'myhost' and $unconfigured is not set, a script should produce the following output:

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

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

I was thinking this could be done in a simple one-liner with some sort of sed/awk magic, but I'm no expert and my searches have been in vein, so appreciate any help.

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

Edit:

编辑:

I should mention that the file can really be any format text file, for example xml. I just want to replace anything that looks like an env variable with whatever is currently set in the environment.

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

采纳答案by Shawn Chin

sed 's/$HOSTNAME/myhost/g;s/$unconfigured//g' yourfile.txt > another_file.txt

update:

更新:

Based on updates in your question, this won't be a good solution.

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

update2 :

更新2:

This is based on an answer to a related question. I've hacked at it (I'm unfamiliar with perl) to remove undefined vars.

这是基于对相关问题的回答。我已经破解了它(我不熟悉 perl)以删除未定义的变量。

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

Should work for any input text file, however you will need to define vars using the ${...}format which simplifies the string matching.

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

(rant regarding the evilness of eval moved to a separate postso as not to confuse readers)

关于 eval 邪恶的咆哮移到一个单独的帖子,以免混淆读者

回答by DarkDust

I'd do it like this:

我会这样做:

# 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

Edit: Or this very nasty thing (I'm sure there's a better way)

编辑:或者这个非常讨厌的东西(我确定有更好的方法)

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

回答by Andy Whitfield

Thanks to @DarkDust I came up with this:

感谢@DarkDust 我想出了这个:

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

回答by Shawn Chin

"eval is evil"

“评估是邪恶的”

This is not an answer, but a warning in response to using eval for this task. You really really reallydon't want to do that.

这不是答案,而是针对使用 eval 执行此任务的警告。你真的真的真的不想那样做。

Exhibit 1: a malicious template file:

图表 1:恶意模板文件:

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

An unsuspecting user:

一个毫无戒心的用户:

[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)

Note the last line!

注意最后一行!

Now, imagine the possibilities....

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

回答by Elias Probst

I used this oneliner to replace ${VARIABLE}style variables in a file:

我使用这个 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

I'm pretty sure someone can do this in 1/3rd of the length using awk… feel challenged! ;)

我很确定有人可以使用 1/3 的长度做到这一点awk……感到有挑战!;)

回答by Aneil Mallavarapu

Here's a short one-liner that uses python's curly brace formatting to safely do the magic:

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

contents=\"\"\"`cat $file`\"\"\"; python -c "import os;print $contents.format(**os.environ)"
  • avoids evil eval
  • allows outputting curly braces: use {{instead of {
  • no need to specify vars explicitly when calling the script
  • 避免邪恶的评估
  • 允许输出花括号:使用{{代替{
  • 调用脚本时无需显式指定变量

For example, given properties file settings.properties:

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

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

Then, do the substitution with:

然后,使用以下方法进行替换:

$ 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}

A script is here: https://raw.githubusercontent.com/aneilbaboo/machome/master/bin/substenv

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

回答by Malvineous

This is what envsubstis for.

envsubst就是为了。

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

You would probably use it more like this though:

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

envsubst < input.txt > output.txt

envsubstseems to be part of GNU gettext.

envsubst似乎是 GNU gettext 的一部分。

回答by Robert Massaioli

Here is a snippet of Javascript that I like to have around for solving this exact problem:

这是我喜欢用来解决这个确切问题的一段 Javascript 代码:

// 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`);
});

Hopefully this helps somebody else.

希望这对其他人有帮助。