当前位置:  开发笔记 > 编程语言 > 正文

如何在文本文件中替换$ {}占位符?

如何解决《如何在文本文件中替换${}占位符?》经验,为你挑选了9个好方法。

我想将"模板"文件的输出传递给MySQL,该文件包含${dbName}散布的变量.什么是命令行实用程序来替换这些实例并将输出转储到标准输出?



1> user..:

塞德!

给出template.txt:

The number is ${i}
The word is ${word}

我们只需要说:

sed -e "s/\${i}/1/" -e "s/\${word}/dog/" template.txt

感谢Jonathan Leffler提示将多个-e参数传递给同一个sed调用.


您可以将这两个sed命令合并为一个:sed -e"s /\$ {i}/1 /" - e"s /\$ {word}/dog /"; 这更有效率.您可能会遇到某些版本的sed可能遇到100个此类操作的问题(多年前的问题 - 可能仍然不是真的,但要注意HP-UX).
你也不需要`cat`.你只需要`sed -e"s /\$ {i}/1 /" - e"s /\$ {word}/dog /"template.text`.
小提示:如果给定示例中的"1"或"dog"包含美元符号,则必须使用反斜杠转义它(否则不会发生替换).
如果替换文本是密码怎么办?在这种情况下,`sed`将期望转义文本,这是一个麻烦.

2> plockc..:

更新

以下是来自yottatsa的类似问题的解决方案,该问题仅替换$ VAR或$ {VAR}等变量,并且是一个简短的单行

i=32 word=foo envsubst < template.txt

当然,如果和你的话语在你的环境中,那么它就是

envsubst < template.txt

在我的Mac上,它看起来像是作为gettextMacGPG2的一部分安装的

老答案

这是对mogsie在类似问题上的解决方案的改进,我的解决方案并不要求你使用双引号,mogsie's,但他是一个单行!

eval "cat < /dev/null

这两个解决方案的优势在于你只能得到几种类型的shell扩展,这些扩展通常不会出现$((...)),`...`和$(...),尽管反斜杠一个转义字符在这里,但你不必担心解析有一个错误,它做多行就好了.


如果你的envars没有导出,我发现裸的`envsubst`不起作用.
@ToddiusZho:没有未导出的环境变量 - 正是导出使_shell_变量成为环境变量.`envsubst`,顾名思义,只识别_environment_变量,而不是_shell_变量.值得注意的是,`envsubst`是一个_GNU_实用程序,因此不会在所有平台上预安装或提供.
感谢"旧答案",因为它不仅允许变量,还有像$(ls -l)这样的shell命令
也许另一种说法是envsubst只看到它自己的进程环境变量,所以你之前定义的"正常"shell变量(在不同的行上)不会被子进程继承,除非你"导出"它们.在我上面使用gettext的示例中,我正在通过bash机制修改继承的gettext环境,方法是将它们添加到我即将运行的命令中

3> gnud..:

使用/bin/sh.创建一个设置变量的小shell脚本,然后使用shell本身解析模板.像这样(编辑以正确处理换行):

文件template.txt:

the number is ${i}
the word is ${word}

文件script.sh:

#!/bin/sh

#Set variables
i=1
word="dog"

#Read in template one line at the time, and replace variables (more
#natural (and efficient) way, thanks to Jonathan Leffler).
while read line
do
    eval echo "$line"
done < "./template.txt"

输出:

#sh script.sh
the number is 1
the word is dog


这非常危险!输入中的所有`bash`命令都将被执行.如果模板是:"单词是; rm -rf $ HOME"你将丢失文件.
@gnud信任文件足以存储它的内容并信任它足以执行它包含的任何内容之间存在差异.
要注意约束:(a)输入中的双引号被静静地丢弃,(b)`read`命令,如所写的,修剪每行的前导和尾随空格并'吃'``字符.,(c)只有在你完全信任或控制输入时才使用它,因为输入中嵌入的命令替换(`\`... \``或`$(...)`允许执行任意命令,因为使用了'eval`.最后,"echo"错误地为其命令行选项之一的行的开头错误.
为什么不:只读:读取线; 做eval echo"$ line"; 完成<./template.txt ??? 没有必要将整个文件读入内存,只需通过密集使用头部和尾部一次吐出一行.但'eval'没问题 - 除非模板包含shell引号等shell字符.

4> Dana the San..:

鉴于最近的兴趣,我再次考虑这个问题,我认为我最初想到的工具是m4autotools的宏处理器.因此,不是我最初指定的变量,而是使用:

$echo 'I am a DBNAME' | m4 -DDBNAME="database name"



5> 小智..:

template.txt

Variable 1 value: ${var1}
Variable 2 value: ${var2}

data.sh

#!/usr/bin/env bash
declare var1="value 1"
declare var2="value 2"

parser.sh

#!/usr/bin/env bash

# args
declare file_data=$1
declare file_input=$2
declare file_output=$3

source $file_data
eval "echo \"$(< $file_input)\"" > $file_output

./parser.sh data.sh template.txt parsed_file.txt

parsed_file.txt

Variable 1 value: value 1
Variable 2 value: value 2



6> 小智..:

这是我基于前一个答案的perl解决方案,替换环境变量:

perl -p -e 's/\$\{(\w+)\}/(exists $ENV{$1}?$ENV{$1}:"missing variable $1")/eg' < infile > outfile


这很棒。不一定总是有perl,但是当您这样做时,这很简单明了。

7> mklement0..:

这是一个强大的Bash功能 - 尽管使用eval- 应该是安全的使用.

${varName}输入文本中的所有变量引用都基于调用shell的变量进行扩展.

没有其他东西被扩展:既没有包含{...}(例如$varName)名称的变量引用,也没有包含命令替换($(...)和遗留语法`...`),也没有算术替换($((...))和遗留语法$[...]).

把a $当作文字来对待\它吧.例如:\${HOME}

请注意,输入仅通过stdin接受.

例:

$ expandVarsStrict <<<'$HOME is "${HOME}"; `date` and \$(ls)' # only ${HOME} is expanded
$HOME is "/Users/jdoe"; `date` and $(ls)

功能源代码:

expandVarsStrict(){
  local line lineEscaped
  while IFS= read -r line || [[ -n $line ]]; do  # the `||` clause ensures that the last line is read even if it doesn't end with \n
    # Escape ALL chars. that could trigger an expansion..
    IFS= read -r -d '' lineEscaped < <(printf %s "$line" | tr '`([$' '\1\2\3\4')
    # ... then selectively reenable ${ references
    lineEscaped=${lineEscaped//$'\4'{/\${}
    # Finally, escape embedded double quotes to preserve them.
    lineEscaped=${lineEscaped//\"/\\\"}
    eval "printf '%s\n' \"$lineEscaped\"" | tr '\1\2\3\4' '`([$'
  done
}

该函数假定没有0x1,0x2,0x3,和0x4控制字符存在于输入,因为那些字符.在内部使用 - 因为函数处理文本,这应该是一个安全的假设.


这是这里最好的答案之一.即使使用"eval",它也是非常安全的.

8> neu242..:

创建rendertemplate.sh:

#!/usr/bin/env bash

eval "echo \"$(cat $1)\""

而且template.tmpl:

Hello, ${WORLD}
Goodbye, ${CHEESE}

渲染模板:

$ export WORLD=Foo
$ CHEESE=Bar ./rendertemplate.sh template.tmpl 
Hello, Foo
Goodbye, Bar



9> Beau Simense..:

如果您愿意使用Perl,那将是我的建议.虽然可能有一些sed和/或AWK专家可能知道如何更容易地做到这一点.如果您有一个更复杂的映射,而不仅仅是dbName用于替换,那么您可以非常轻松地扩展它,但是您也可以将其放入标准的Perl脚本中.

perl -p -e 's/\$\{dbName\}/testdb/s' yourfile | mysql

一个简短的Perl脚本,可以做一些稍微复杂的事情(处理多个键):

#!/usr/bin/env perl
my %replace = ( 'dbName' => 'testdb', 'somethingElse' => 'fooBar' );
undef $/;
my $buf = ;
$buf =~ s/\$\{$_\}/$replace{$_}/g for keys %replace;
print $buf;

如果将上述脚本命名为replace-script,则可以按如下方式使用它:

replace-script < yourfile | mysql


使用perl比尝试使用shell要简单得多.花时间做这项工作,而不是尝试一些其他提到的基于shell的解决方案.
使用perl可以通过多种方式实现此目的,这取决于您希望如何复杂和/或安全.更复杂的例子可以在这里找到:http://www.perlmonks.org/?node_id = 718936
推荐阅读
mobiledu2402851377
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有