我想用我的模板文件(使用find递归找到)替换相应的值。密钥将从属性文件加载。请参阅下面的脚本:
脚本文件内容:
. /home/uname/config/appl.properties
echo ${name_1}
echo ${age_1}
job_1="IT"
echo ${job_1}
for file in $(find /home/uname/config -name "*.txt"); do
echo $file
temp_file="/home/uname/temp_file.txt"
cp -f $file $temp_file
rm $file
envsubst < $temp_file > $file
done
appl.properties内容:
name_1="theBestName"
age_1="25"
template.txt内容:
My name is ${name_1}, my age is ${age_1} and my job is in ${job_1}.
我能够加载键/值对(echo语句显示键值),但是当envsubst写出模板文件时,它不会用值替换任何键。我得到的输出是:
My name is and my age is and my job is in .
答案 0 :(得分:2)
envsubst
要求其键/值对位于环境变量中。仅仅分配就会创建shell变量,而不是环境变量。
以下是尝试更换最佳做法:
set -a # turn on auto-export
. appl.properties
set -a # turn off auto-export
while IFS= read -r -d '' filename; do
tempfile=$(mktemp "$filename.XXXXXX")
if envsubst <"$filename" >"$tempfile"; then
mv "$tempfile" "$filename"
else
rm -f "$tempfile"
fi
done < <(find /home/uname/config -name '*.txt' -print0)
关键点:
set -a
可确保其设置的变量存在于环境中。IFS= read -r -d '' filename
迭代来自NUL分隔源(例如find -print0
)的名称 - 与for filename in $(find ...)
不同 - 确保您的代码正确处理带空格的文件名,文件名为名字中的圆圈字符,以及其他不常见的情况。while read ...; done < <(find ...)
代替find ... | while read
可以避免BashFAQ #24中记录的错误,其中循环中设置的变量不会持久存在。有关通过此方法和/或BashFAQ #1页面逐行阅读流的详情,请参阅UsingFind。mktemp
生成临时文件名可以防止出现符号链接攻击 - 想想如果其他人有权写入/home/uname/
,但没有权限写入的话会发生什么/etc
,为/etc/passwd
(或您关注的任何其他文件)创建了一个名为/home/uname/temp_file.txt
的符号链接。此外,使用mktemp
生成随机名称意味着同一脚本的多个并发实例不会踩在同一个临时文件名上。envsubst
的输出写入临时文件,然后将该临时文件重命名为目标名称,可确保在生成完成之前不会覆盖输出。因此,即使进程在部分完成时被中断,您也可以保证输出文件保持原始状态或完全写入(详细信息取决于文件系统的配置和语义)。答案 1 :(得分:0)
> $file
在envsubst
开始之前截断文件。
使用来自moreutils的sponge(1)来解决这个问题,或编写自己的海绵,在写出之前捕获所有输入。