考虑您的试用版:
cat test | sed -e "s/\(\${[A-Z]*}\)/`eval "echo '\1'"`/" > outputfile
这不起作用的原因是它需要 shell 的先见之明。 sed 脚本是在 sed 匹配任何模式之前生成的,因此 shell 无法为您完成这项工作。
我过去曾以几种方式做到这一点。通常,我有一个已知变量及其值的列表,并且我已经从该列表中进行了替换:
for var in PATH VARIABLE USERNAME
do
echo 's%${'"$var"'}%'$(eval echo "\$$var")'%g'
done > sed.script
cat test | sed -f sed.script > outputfile
如果你想任意映射变量,那么你要么需要处理整个环境(而不是变量名的固定列表,使用来自env 的输出,适当编辑),要么使用 Perl 或 Python。
请注意,如果环境变量的值在您的版本中包含斜杠,那么在 s/// 表示法中使用斜杠作为字段分隔符时会遇到问题。我使用了 '%',因为使用它的环境变量相对较少 - 但在某些机器上发现了一些确实包含 '%' 字符,因此完整的解决方案更加棘手。您还需要担心值中的反斜杠。您可能必须使用“$(eval echo "\$$var" | sed 's/[\%]/\\&/g')”之类的东西来转义环境变量值中的反斜杠和百分号。最后的问题:sed 的某些版本对脚本大小有(或有)有限的容量 - 旧版本的 HP-UX 有大约 100 个限制。我不确定这是否仍然是一个问题,但它是就在 5 年前。
对原剧本的简单改编如下:
env |
sed 's/=.*//' |
while read var
do
echo 's%${'"$var"'}%'$(eval echo "\$$var" | sed 's/[\%]/\\&/g')'%g'
done > sed.script
cat test | sed -f sed.script > outputfile
但是,更好的解决方案是利用您已经拥有来自 env 的输出中的值这一事实,因此我们可以这样写:
env |
sed 's/[\%]/\\&/g;s/\([^=]*\)=\(.*\)/s%${\1}%\2%/' > sed.script
cat test | sed -f sed.script > outputfile
这完全安全,因为 shell 从不评估任何不应该评估的东西 - 你必须非常小心变量值中的 shell 元字符。我认为,如果env 的某些输出格式错误,此版本可能会遇到任何问题。
当心 - 用 sed 编写 sed 脚本是一项深奥的职业,但它说明了好工具的力量。
所有这些例子都没有清理临时文件。