一次性填充文件中的占位符

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)\"")" > $outputfile echo "$(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' &lt;file&gt; ... 参考:@ 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!)

【讨论】:

以上是关于一次性填充文件中的占位符的主要内容,如果未能解决你的问题,请参考以下文章

Android布局中的占位符文本(仅限设计过程)?

解析文件以使用值填充占位符

Firefox 输入占位符填充问题

尝试填充占位符时出现Tensorflow错误

Chrome 正在使用占位符自动填充我的 select2 输入

如何打印 Perl 的 DBI 填充占位符后执行的 SQL 查询?