使用Shell脚本读取和替换键值属性

时间:2016-06-24 21:49:41

标签: shell unix

我想用我的模板文件(使用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 .

2 个答案:

答案 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)

> $fileenvsubst开始之前截断文件。 使用来自moreutils的sponge(1)来解决这个问题,或编写自己的海绵,在写出之前捕获所有输入。