替换文件中所有占位符的bash脚本

6

我正在尝试编写一个Bash脚本,用于将文件中所有占位符的出现替换为同名的环境变量。例如,如果我有一个如下所示的文件...

This is an {{VAR1}} {{VAR2}}.
It should work across multiple lines in this {{VAR2}}.

我有以下环境变量设置:

VAR1='example'
VAR2='file'

在运行脚本后,我应该得到以下输出结果:
This is an example file.
It should work across multiple lines in this file.

我相信可以使用awk/sed找到解决方案,但目前为止,最接近的方法无法处理一行中有多个变量的情况。以下是我迄今为止的尝试:

cat example.txt | grep -o '{{.*}}' > temp
while read placeholder; do
  varName=$(echo "$placeholder" | tr -d '{}')
  value="${!varName}"
  sed -i "s/$placeholder/$value/g" "$file"
done < temp
rm -rf temp

您是否考虑过使用m4宏处理器? - Mark Setchell
@MarkSetchell 我没听说过m4,但我会去了解一下。谢谢。 - Anton
3个回答

7
我会使用Perl语言:
perl -pe 's/{{(.*?)}}/$ENV{$1}/g' filename

这假设VAR1VAR2 是环境变量(即被export出来的),这样Perl就可以从环境中选出它们。对于任何不是纯shell的方法都需要这样做;我只是提到它以避免混淆。
其工作原理如下:
  • s/pattern/replacement/g 是替换命令;您可能会在sed中认识它。区别在于,我们可以使用Perl更强大的正则表达式引擎和变量。g标志使所有匹配项都被替换;如果没有它,它将仅适用于第一个。
  • 在模式中,.*? 非贪婪地匹配,因此在包含foo {{VAR1}} bar {{VAR2}} baz的行中,模式{{.*?}} 仅匹配{{VAR1}}而不是{{VAR1}} bar {{VAR2}}
  • 介于{{}}之间的部分被捕获,因为它在()之间并且可以重复使用为$1
  • 替换中的$ENV{$1}使用了特殊的%ENV哈希表,其中包含Perl进程的环境。$ENV{$1}是名称为$1的环境变量的值,这是之前捕获的组。

这太棒了 - 正是我正在寻找的!谢谢 @Wintermute! - Anton
在运行此脚本之前,请确保在脚本中导出VAR1 VAR2,否则它将无法正常工作。 - user636044

3

仅限使用 bashsed

$ VAR1='example'
$ VAR2='file'
$ export VAR1 VAR2

$ sed -e '{s/{{\([^{]*\)}}/${\1}/g; s/^/echo "/; s/$/";/}' -e e filename
This is an example file.
It should work across multiple lines in this file.
  • sed -e '{s/{{\([^{]*\)}}/${\1}/g;}' filename:

    This is an ${VAR1} ${VAR2}.
    It should work across multiple lines in this ${VAR2}.
    
    • {{\([^{]*\)}} - Search for {{..}}
    • [^{] - Non greedy match
    • \1 - Access to the bracketed values \(...\).
  • sed -e '{s/{{\([^{]*\)}}/${\1}/g; s/^/echo "/; s/$/";/}' filename:

    echo "This is an ${VAR1} ${VAR2}.";
    echo "It should work across multiple lines in this ${VAR2}.";
    
    • s/^/echo "/ - Replace the beginning of the line with echo "
    • s/$/";/ - Replace the end of the line with ";

1
我只是在尝试你原来的方法。在$varName上添加另一个循环不会起作用吗?
cat example.txt | grep -o '{{.*}}' > temp
while read placeholder; do
    varName=$(echo "$placeholder" | tr -d '{}')
    for i in $varName; do
        value="${!i}"
        sed -i "s/{{$i}}/$value/g" example.txt
    done
done < temp
rm -rf temp

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接