如何在复杂的文本文件中替换shell变量

时间:2013-01-04 10:43:49

标签: linux shell

我有几个文本文件,其中我引入了shell变量(例如$ VAR1或$ VAR2)。

我想将这些文件(逐个)保存在新文件中,其中所有变量都已被替换。

为此,我使用了以下shell脚本(在StackOverflow上找到):

while read line
do
    eval echo "$line" >> destination.txt
done < "source.txt"

这非常适用于非常基本的文件。

但是对于更复杂的文件,“eval”命令做得太多了:

  • 跳过以“#”开头的行

  • XML文件解析导致大量错误

有更好的方法吗? (在shell脚本中......我知道这很容易用Ant完成)

亲切的问候

11 个答案:

答案 0 :(得分:126)

看起来,我的系统发现有一个envsubst命令,它是gettext-base包的一部分。

所以,这很容易:

envsubst < "source.txt" > "destination.txt"

答案 1 :(得分:48)

在参考答案2时,在讨论envsubst时,你问“我怎样才能使用我的.sh脚本中声明的变量?”

答案是您只需在调用envsubst之前导出变量。

您还可以使用envsubst SHELL_FORMAT参数限制输入中要替换的变量字符串(避免输入中的字符串意外替换为常见的shell变量值 - 例如$ HOME)。

例如:

export VAR1='somevalue' VAR2='someothervalue'
MYVARS='$VAR1:$VAR2'

envsubst "$MYVARS" <source.txt >destination.txt

将source.txt中的$ VAR1和$ VAR2(以及仅VAR1和VAR2)的所有实例分别替换为'somevalue'和'someothervalue'。

答案 2 :(得分:7)

我知道这个话题很老,但我有一个更简单的工作解决方案而不导出变量。可以是oneliner,但我更喜欢在行尾使用\进行拆分。

var1='myVar1'\
var2=2\
var3=${var1}\
envsubst '$var1,$var3' < "source.txt" > "destination.txt"

#         ^^^^^^^^^^^    ^^^^^^^^^^     ^^^^^^^^^^^^^^^
# define which to replace   input            output

需要将变量定义到与envsubst相同的行,以便将其视为环境变量。

'$var1,$var3'是可选的,仅替换指定的${VARIABLE_USED_BY_JENKINS}。想象一下包含{ "resources": [ { "type": "Microsoft.BotService/botServices", "sku": { "name": "[parameters('sku')]" }, "kind": "[parameters('kind')]", "name": "[parameters('botId')]", "apiVersion": "2017-12-01", "location": "global", "properties": { "name": "[parameters('botId')]", "displayName": "[parameters('botId')]", "endpoint": "[variables('botEndpoint')]", "msaAppId": "[parameters('appId')]", "developerAppInsightsApplicationId": "[variables('insightsName')]", "developerAppInsightKey": "[reference(resourceId('microsoft.insights/components/', variables('insightsName')), '2015-05-01').InstrumentationKey]", "enabledChannels": [ "webchat", "directline", "facebook" ], "configuredChannels": [ "webchat", "facebook" ] }, "dependsOn": [ "[resourceId('microsoft.insights/components/', variables('insightsName'))]" ] } ] 的输入文件,不应该被替换。

答案 3 :(得分:5)

  1. 定义您的ENV变量
  2. $ export MY_ENV_VAR=congratulation
    
    1. 使用以下内容创建模板文件( in.txt
    2. $MY_ENV_VAR
      

      您还可以使用系统定义的所有其他ENV变量,如(在linux中)$ TERM,$ SHELL,$ HOME ......

      1. 运行此命令以放置 in.txt 文件中的所有env变量,并将结果写入 out.txt
      2. $ envsubst "`printf '${%s} ' $(sh -c "env|cut -d'=' -f1")`" < in.txt > out.txt
        
        1. 检查out.txt文件的内容
        2. $ cat out.txt
          

          你应该看到“祝贺”。

答案 4 :(得分:1)

while IFS='=' read -r name value ; do
    # Print line if found variable
    sed -n '/${'"${name}"'}/p' docker-compose.yml
    # Replace variable with value. 
    sed -i 's|${'"${name}"'}|'"${value}"'|' docker-compose.yml
done < <(env)

注意:变量名或值不应包含“|”,因为它被用作分隔符。

答案 5 :(得分:0)

如果你真的只想使用bash(和sed),那么我会浏览你的每个环境变量(在posix模式下由set返回)并构建一堆-e 'regex' for从那里开始,由-e 's/\$[a-zA-Z_][a-zA-Z0-9_]*//g'终止,然后将所有这些传递给sed。

Perl会做一个更好的工作,你可以访问环境vars作为一个数组,你可以做可执行的替换,所以你只匹配任何环境变量一次。

答案 6 :(得分:0)

实际上您需要将read更改为read -r,这会使其忽略反斜杠。

此外,您应该转义引号和反斜杠。 所以

while read -r line; do
  line="${line//\\/\\\\}"
  line="${line//\"/\\\"}"
  line="${line//\`/\\\`}"
  eval echo "\"$line\""
done > destination.txt < source.txt

尽管如此仍然是一种可怕的扩张方式。

答案 7 :(得分:0)

envsubst似乎与我想要使用的内容完全相同,但-v选项让我感到有些惊讶。

虽然envsubst < template.txt工作正常,但选项-v的工作正常无效:

$ cat /etc/redhat-release
Red Hat Enterprise Linux Server release 7.1 (Maipo)
$ envsubst -V
envsubst (GNU gettext-runtime) 0.18.2
Copyright (C) 2003-2007 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.
Written by Bruno Haible.

正如我所写,这不起作用:

$ envsubst -v < template.txt
envsubst: missing arguments
$ cat template.txt | envsubst -v
envsubst: missing arguments

我必须这样做才能让它发挥作用:

TEXT=`cat template.txt`; envsubst -v "$TEXT"

也许对某人有所帮助。

答案 8 :(得分:0)

导出所有需要的变量,然后使用perl onliner

TEXT=$(echo "$TEXT"|perl -wpne 's#\${?(\w+)}?# $ENV{$1} // $& #ge;')

这将用实际值替换TEXT中存在的所有ENV变量。 行情也保留了:)

答案 9 :(得分:0)

如果要在源文件中替换环境变量,同时保持所有非环境变量不变,则可以使用以下命令:

envsubst "$(printf '${%s} ' $(env | sed 's/=.*//'))" < source.txt > destination.txt

仅替换特定变量的语法为explained here。上面的命令使用子外壳列出所有定义的变量,然后将其传递到envsubst

因此,如果有一个名为$NAME的已定义环境变量,并且您的source.txt文件如下所示:

Hello $NAME
Your balance is 123 ($USD)

destination.txt将是:

Hello Arik
Your balance is 123 ($USD)

请注意,$NAME已被替换,$USD保持不变

答案 10 :(得分:0)

以单引号运行perl代码(-pi),在搜索和替换每行模式(-e中调用perl二进制文件,该代码在特殊的{ {1}}散列包含导出的变量名作为键,导出的变量值作为键的值,并且对于每次迭代,只需将包含%ENV的字符串替换为其$<<key>>

<<value>>

注意事项: 如果两个或多个var以相同的字符串开头,则需要额外的逻辑处理。