一次性填充文件中的占位符
Posted
技术标签:
【中文标题】一次性填充文件中的占位符【英文标题】:Fill placeholders in file in single pass 【发布时间】:2010-09-29 06:25:31 【问题描述】:我有一个带有占位符字符串的框架文本文件:
blah blah blah
blah $PLACEHOLDER_1$
blah
$PLACEHOLDER_2$
等等。占位符的具体“形式”无关紧要——我可以将它们更改为最适合具体实施的任何形式。
我有一个 bash 脚本,我知道占位符的值,我需要生成一个新文件,将占位符替换为值。
#! /bin/sh
PLACEHOLDER_1 = 'string 1'
PLACEHOLDER_2 = 'multiline
string
2'
# TODO: Generate file output.txt from file output.template
# using placeholders above.
我可以使用 sed 多次执行此操作,但这并不有趣。我确实不想使用 Perl。我只想使用 textutils 和 bash 本身。
一次性完成我想做的事情的最佳方法是什么?
【问题讨论】:
等号周围不能有空格。 【参考方案1】:这是一种不用 sed 的方法:
首先,一个稍微修改的模板文件,其中占位符是 bash 变量:
blah blah blah
blah $PLACEHOLDER_1
blah
$PLACEHOLDER_2
还有脚本:
#! /bin/sh
templatefile=output.template
outputfile=output.txt
PLACEHOLDER_1='string 1'
PLACEHOLDER_2='multiline
string
2'
# DONE: Generate file output.txt from file output.template
# using placeholders above.
echo "$(eval "echo \"$(cat $templatefile)\"")" > $outputfile
这是一个演示脚本中包含的模板的版本,但有所不同。它还演示了默认值,也可以在模板文件版本中使用,而且您可以在模板中进行数学运算:
#! /bin/sh
template='blah blah blah
blah $PLACEHOLDER_1
blah
$PLACEHOLDER_2:-"some text" blah $PLACEHOLDER_3:-"some
lines
of
text" and the total is: $(($VAL_1:-0 + $VAL_2:-0))'
# default operands to zero (or 1) to prevent errors due to unset variables
outputfile=output.txt
# gears spin, bells ding, values for placeholders are computed
PLACEHOLDER_1='string 1'
PLACEHOLDER_2='multiline
string
2'
VAL_1=2
VAL_2=4
unset PLACEHOLDER_3 # so we can trigger one of the defaults
# Generate file output.txt from variable $template
# using placeholders above.
echo "$(eval "echo \"$template\"")" > $outputfile
没有 sed,没有循环,只有毛茸茸的嵌套和引号。我很确定所有引用都会保护您免受模板文件中的恶意内容的侵害,但我不保证这一点。
【讨论】:
您可以在任一回显上使用 -e 来解释反斜杠转义,例如模板和/或占位符中的 \n。 不。不安全。模板可以包含可能做坏事的“$(command)”。您必须知道您是否可以信任您的模板。您已收到警告。 谁在乎它是否安全,除非您将它提供给用户?我需要它根据我完全控制的内容自动生成一些 html。 :) +1! 顺便说一句,如果你需要在结果中保留引号,你可以先用 sed 转义它们: echo "$(eval "echo \"$(sed 's/\"/\\\"/ g' $template)\"")" > $outputfileecho "$(eval "echo \"$template\"")" > $outputfile
在脚本中对我不起作用,但在命令行中起作用。为什么?【参考方案2】:
您仍然可以使用 sed 一次性完成替换。您只需在一个命令中指定所有替换。
例如。
sed -i 's/PLACEHOLDER_1/string 1/g;s/PLACEHOLDER_2/string 2/g' <file>
【讨论】:
如果您真的知道自己在做什么并且不想进行备份,则需要在 OSX 上为 -i 选项提供一个空字符串:sed -i '' 's/PLACEHOLDER_1/string 1/g;s/PLACEHOLDER_2/string 2/g' <file>
... 参考:@ 987654321@
不起作用,它似乎在做第二遍。回声“AB” | sed 's/A/B/g;s/B/A/g' 返回 AA,而不是 BA。输入中 A 和 B 之间的换行也会发生。
您期望发生什么?您是说替换 A->B,然后将其替换回 B->A。您是希望它们单独执行还是作为单个表达式执行?【参考方案3】:
在上一个答案的基础上,也许使用数组并计算 sed 字符串?
#!/bin/sh
PLACEHOLDER[0]='string 1'
PLACEHOLDER[1]='multiline
string
2'
s="sed -i "
for(( i=0 ; i<$#PLACEHOLDER[*] ; i++ )) ; do
echo $PLACEHOLDER[$i]
s=$s"s/PLACEHOLDER_$i/$PLACEHOLDER[$i]/g;"
done
echo $s
不过,似乎在多行字符串上失败了。
我不知道 Bash 数组的可移植性如何。以上 sn-p 使用“GNU bash,版本 3.2.17(1)-release (i386-apple-darwin9.0)”进行测试
【讨论】:
这是因为您需要在带有空格的参数周围加上引号。将“sed -i”更改为“sed -i'”,然后在循环添加另一个引号之后它应该可以工作。 你说“用 bash 测试”,但你的 shebang 说“sh”。 sh 是否链接到您系统上的 bash?如果是,它的行为不取决于它的名字吗? sh 在我的系统上是 bash,但(奇怪的是)它没有链接。我有 /bin/sh 和 bin/bash,两个不同的文件。我想是 Mac 的一个怪癖。我不知道如果 GNU bash 被调用为“sh”而不是被调用为“bash”,它是否会改变它的行为。【参考方案4】:我唯一的 bash 解决方案:
TEMPLATE='
foo
$var1
bar
$var2'
eval "echo \"$TEMPLATE\""
【讨论】:
【参考方案5】:我只是偶然发现了这个问题,因为我只是在寻找完全相同的问题,然后我找到了envsubst(1)
。
如果你不介意使用环境变量,你可以使用 envsubst:
PLACEHOLDER_1='string 1' PLACEHOLDER_2='multiline
string
2' envsubst < output.template
如果您有很多变量,您可以将它们存储在一个文件中,只需 source
即可(记得在源文件末尾使用 export
!)
【讨论】:
以上是关于一次性填充文件中的占位符的主要内容,如果未能解决你的问题,请参考以下文章