如何在复杂文本文件中替换 shell 变量
- 2024-10-22 08:28:00
- admin 原创
- 59
问题描述:
我有几个文本文件,其中引入了 shell 变量(例如 $VAR1 或 $VAR2)。
我想(逐个)获取这些文件并将它们保存到新文件中,其中所有变量都将被替换。
为此,我使用了以下 shell 脚本(在 StackOverflow 上找到):
while read line
do
eval echo "$line" >> destination.txt
done < "source.txt"
这对于非常基本的文件非常有效。
但是对于更复杂的文件,“eval”命令的作用就太大了:
跳过以“#”开头的行
XML 文件解析导致大量错误
有没有更好的方法呢?(在 shell 脚本中...我知道例如用 Ant 就可以轻松完成)
亲切的问候
解决方案 1:
经查看,发现我的系统上有一个envsubst
命令,它是 gettext-base 包的一部分。
因此,这变得简单:
envsubst < "source.txt" > "destination.txt"
请注意,如果您想对两者使用相同的文件,则必须使用 moreutil 之类的东西sponge
,正如 Johnny Utahh 所建议的那样:envsubst < "source.txt" | sponge "source.txt"
。(因为 shell 重定向会在读取之前清空文件。)
解决方案 2:
参考答案 2,在讨论 envsubst 时,您问道:
我如何使其与我的 .sh 脚本中声明的变量一起工作?
答案是您只需要在调用之前导出变量envsubst
。
您还可以使用参数限制要在输入中替换的变量字符串envsubst
SHELL_FORMAT
(避免用常见的 shell 变量值意外替换输入中的字符串 - 例如$HOME
)。
例如:
export VAR1='somevalue' VAR2='someothervalue'
MYVARS='$VAR1:$VAR2'
envsubst "$MYVARS" <source.txt >destination.txt
将分别用和替换 中的所有$VAR1
和$VAR2
(且仅VAR1
和VAR2
)实例。source.txt
`'somevalue'`'someothervalue'
解决方案 3:
我知道这个主题已经过时了,但我有一个更简单的解决方案,无需导出变量。可以是一行代码,但我更喜欢使用``行尾进行拆分。
var1='myVar1'\nvar2=2\nvar3=${var1}\nenvsubst '$var1,$var3' < "source.txt" > "destination.txt"
# ^^^^^^^^^^^ ^^^^^^^^^^ ^^^^^^^^^^^^^^^
# define which to replace input output
变量需要定义到同一行envsubst
才能被视为环境变量。
可选'$var1,$var3'
的仅替换指定的。想象一下包含${VARIABLE_USED_BY_JENKINS}
不应替换的输入文件。
解决方案 4:
定义 ENV 变量
$ export MY_ENV_VAR=congratulation
创建模板文件(in.txt),内容如下
$MY_ENV_VAR
您还可以使用系统定义的所有其他 ENV 变量,如(在 Linux 中)$TERM、$SHELL、$HOME……
运行此命令替换in.txt文件中的所有环境变量,并将结果写入out.txt
$ envsubst "`printf '${%s} ' $(sh -c "env|cut -d'=' -f1")`" < in.txt > out.txt
检查out.txt文件的内容
$ cat out.txt
您应该会看到“祝贺”。
解决方案 5:
还有这个选项:
在文件中定义变量
$ 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"
解决方案 6:
如果您希望在源文件中替换环境变量,同时保留所有非环境变量,则可以使用以下命令:
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
保持不变
解决方案 7:
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)
注意:变量名称或值不应包含“|”,因为它用作分隔符。
解决方案 8:
实际上,您需要将您的更改read
为read -r
,以使其忽略反斜杠。
另外,你应该转义引号和反斜杠。所以
while read -r line; do
line="${line//\\/\\\\}"
line="${line//\"/\\\"}"
line="${line//`/\\`}"
eval echo "\"$line\""
done > destination.txt < source.txt
但仍然是一种糟糕的扩张方式。
解决方案 9:
如果您真的只想使用 bash(和 sed),那么我会遍历您的每个环境变量(如在 posix 模式下返回的)并从中set
构建一堆for sed,以 终止,然后将所有这些传递给 sed。-e 'regex'
`-e 's/$a-zA-Z_*//g'`
然而,Perl 可以做得更好,您可以将环境变量作为数组访问,并可以进行可执行替换,因此您只需匹配任何环境变量一次。
解决方案 10:
导出所有需要的变量,然后使用 perl onliner
TEXT=$(echo "$TEXT"|perl -wpne 's#${?(w+)}?# $ENV{$1} // $& #ge;')
这将用实际值替换 TEXT 中存在的所有 ENV 变量。引号也会被保留 :)
解决方案 11:
-pi
通过在单引号中运行 perl 代码( the ),调用 perl 二进制文件,以按行搜索和替换模式( the )进行搜索和替换-e
,该代码遍历包含导出的变量名作为键、导出的变量值作为键值的特殊哈希的键,并且每次迭代都简单地用其%ENV
替换包含 的字符串。$<<key>>
`<<value>>`
perl -pi -e 'foreach $key(sort keys %ENV){ s/$$key/$ENV{$key}/g}' file
警告:当两个或多个变量以相同的字符串开头时,需要额外的逻辑处理...
解决方案 12:
这是递归变量替换:
#!/bin/sh
find ./abc -type f | while read file;
do
FF="$file";
envsubst < ${FF} > ${FF}.replaced
rm ${FF}
mv ${FF}.replaced ${FF}
echo "Replacing ${FF}"
done
解决方案 13:
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"
也许它能对某些人有帮助。
- 2024年20款好用的项目管理软件推荐,项目管理提效的20个工具和技巧
- 2024年开源项目管理软件有哪些?推荐5款好用的项目管理工具
- 项目管理软件有哪些?推荐7款超好用的项目管理工具
- 项目管理软件哪个最好用?盘点推荐5款好用的项目管理工具
- 项目管理软件有哪些最好用?推荐6款好用的项目管理工具
- 项目管理软件有哪些,盘点推荐国内外超好用的7款项目管理工具
- 2024项目管理软件排行榜(10类常用的项目管理工具全推荐)
- 项目管理软件排行榜:2024年项目经理必备5款开源项目管理软件汇总
- 2024年常用的项目管理软件有哪些?推荐这10款国内外好用的项目管理工具
- 项目管理必备:盘点2024年13款好用的项目管理软件