121

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

我想把这些文件(一个一个)保存在所有变量都被替换的新文件中。

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

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

这对非常基本的文件非常有效。

但是在更复杂的文件上,“eval”命令做的太多了:

  • 以“#”开头的行被跳过

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

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

亲切的问候

4

12 回答 12

269

看,原来在我的系统上有一个envsubst命令,它是 gettext-base 包的一部分。

所以,这很容易:

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

请注意,如果您想对两者使用相同的文件,则必须使用类似 moreutil's 的东西sponge,正如 Johnny Utahh 所建议的那样:envsubst < "source.txt" | sponge "source.txt"。(因为 shell 重定向会在读取之前清空文件。)

于 2013-01-04T12:54:10.743 回答
81

关于答案 2,在讨论 envsubst 时,您问:

如何使它与在我的 .sh 脚本中声明的变量一起工作?

答案是您只需在调用envsubst.

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

例如:

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

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

将分别用and替换$VAR1and的所有实例$VAR2(并且只有VAR1and VAR2)。source.txt'somevalue''someothervalue'

于 2014-01-21T17:31:18.823 回答
22

我知道这个话题很老,但我有一个更简单的工作解决方案,无需导出变量。可以是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}想象一个包含不应被替换的输入文件。

于 2018-02-13T08:35:24.190 回答
11
  1. 定义你的 ENV 变量
$ export MY_ENV_VAR=congratulation
  1. 使用以下内容创建模板文件 ( in.txt )
$MY_ENV_VAR

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

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

你应该看到“祝贺”。

于 2018-01-16T12:21:59.603 回答
4

如果您希望在源文件中替换 env 变量,同时保留所有非 env 变量,您可以使用以下命令:

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

此处解释了仅替换特定变量的语法。上面的命令使用子 shell 列出所有定义的变量,然后将其传递给envsubst

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

Hello $NAME
Your balance is 123 ($USD)

destination.txt是:

Hello Arik
Your balance is 123 ($USD)

请注意,$NAME被替换了,而$USD则保持不变

于 2020-05-11T17:17:49.223 回答
3

还有这个选项:

在文件中定义变量

$ cat variables.env 
# info about what this var is
export var1=a
# info about var again
export var2=b

定义一个使用变量的模板文件

$ cat file1-template.txt
This is var1: "${var1}"
This is var2: "${var2}"

生成最终文件,将变量替换为值

$ source variables.env
$ envsubst < file1-template.txt > file1.txt
$ cat file1.txt 
This is var1: "a"
This is var2: "b"
于 2021-12-06T15:54:17.337 回答
2
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)

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

于 2021-02-16T19:14:35.023 回答
0

如果您真的只想使用 bash (和 sed),那么我将检查您的每个环境变量(由setposix 模式返回)并从中构建一堆-e 'regex'for sed ,以 a 终止-e 's/\$[a-zA-Z_][a-zA-Z0-9_]*//g',然后将所有这些传递给赛德。

Perl 会做得更好,您可以将环境变量作为数组访问,并且可以执行可执行替换,因此您只匹配任何环境变量一次。

于 2013-01-04T11:03:02.280 回答
0

实际上,您需要更改您的readto read -rwhich 将使其忽略反斜杠。

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

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

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

于 2013-01-04T11:07:23.160 回答
0

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

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

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

于 2017-09-15T07:14:40.873 回答
0

-pi通过在单引号中运行 perl 代码 ( the ) 在每行模式 ( the ) 中搜索和替换 perl 二进制文件,该代码-e迭代%ENV包含导出变量名称作为键和导出变量值的特殊哈希的键键的值和每次迭代简单地将包含 a 的字符串替换$<<key>>为其<<value>>.

 perl -pi -e 'foreach $key(sort keys %ENV){ s/\$$key/$ENV{$key}/g}' file

警告:对于两个或多个变量以相同字符串开头的情况,需要额外的逻辑处理......

于 2020-08-17T04:55:20.597 回答
-1

envsubst看起来完全像我想使用的东西,但-v选项让我有点惊讶。

虽然envsubst < template.txt工作正常,但 option-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"

也许它可以帮助某人。

于 2017-07-03T10:37:32.543 回答