如何替换文本文件中的 ${} 占位符?
我想将“模板”文件的输出通过管道传输到 MySQL,该文件散布有诸如 ${dbName}
之类的变量。 用于替换这些实例并将输出转储到标准输出的命令行实用程序是什么?
输入文件被认为是安全的,但可能存在错误的替换定义。 执行替换应避免执行意外的代码。
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(19)
更新:尝试 envsubst
这是来自 yottatsa 的类似问题的解决方案,该解决方案仅替换 $VAR 或 ${ 等变量 当然,
如果i和word在你的环境中,那么它只是
在我的Mac上,看起来它是作为一部分安装的gettext 和 MacGPG2
旧答案:尝试 eval
这是对 mogsie 在类似的问题上,我的解决方案不需要您转义双引号,mogsie 需要转义,但他是一个衬垫!
这两种解决方案的强大之处在于,您只能获得几种通常不会发生的 shell 扩展 $((...))、`...` 和 $(...),尽管反斜杠 在这里是一个转义字符,但是您不必担心解析有错误,并且它可以很好地处理多行。
Update: Try envsubst
Here is a solution from yottatsa on a similar question that only does replacement for variables like $VAR or ${VAR}, and is a brief one-liner
Of course if i and word are in your environment, then it is just
On my Mac it looks like it was installed as part of gettext and from MacGPG2
Old Answer: Try eval
Here is an improvement to the solution from mogsie on a similar question, my solution does not require you to escape double quotes, mogsie's does, but his is a one liner!
The power on these two solutions is that you only get a few types of shell expansions that don't occur normally $((...)), `...`, and $(...), though backslash is an escape character here, but you don't have to worry that the parsing has a bug, and it does multiple lines just fine.
Sed!
鉴于 template.txt:
我们只需说:
感谢 Jonathan Leffler 提供了将多个
-e
参数传递给同一个sed
调用的提示。Sed!
Given template.txt:
we just have to say:
Thanks to Jonathan Leffler for the tip to pass multiple
-e
arguments to the samesed
invocation.使用
/bin/sh
。 创建一个设置变量的小 shell 脚本,然后使用 shell 本身解析模板。 像这样(编辑以正确处理换行符):文件 template.txt:
文件 script.sh:
输出:
Use
/bin/sh
. Create a small shell script that sets the variables, and then parse the template using the shell itself. Like so (edit to handle newlines correctly):File template.txt:
File script.sh:
Output:
鉴于最近的兴趣,我又在考虑这个问题,我认为我最初想到的工具是
m4
,自动工具的宏处理器。 因此,您可以使用以下命令来代替我最初指定的变量:I was thinking about this again, given the recent interest, and I think that the tool that I was originally thinking of was
m4
, the macro processor for autotools. So instead of the variable I originally specified, you'd use:创建
rendertemplate.sh
:和
template.tmpl
:渲染模板:
Create
rendertemplate.sh
:And
template.tmpl
:Render the template:
template.txt
data.sh
parser.sh
parsed_file.txt
template.txt
data.sh
parser.sh
parsed_file.txt
这是我基于之前答案的 perl 解决方案,替换了环境变量:
here's my solution with perl based on former answer, replaces environment variables:
这是一个强大的 Bash 函数,尽管使用了
eval
,但应该可以安全使用。输入文本中的所有
${varName}
变量引用都会根据调用 shell 的变量进行扩展。没有其他内容被扩展:名称未包含在
{...}
中的变量引用(例如$varName),也不是命令替换(
$(...)
和旧语法`...`
),也不是算术替换($((.. .))
和旧语法$[...]
)。要将
$
视为文字,请使用\
将其转义; 例如:\${HOME}
请注意,仅通过 stdin 接受输入。
示例:
函数源代码:
函数假设没有
0x1
、0x2
、0x3
和0x4
控制字符出现在输入中,因为这些字符。 在内部使用 - 由于该函数处理文本,这应该是一个安全的假设。Here's a robust Bash function that - despite using
eval
- should be safe to use.All
${varName}
variable references in the input text are expanded based on the calling shell's variables.Nothing else is expanded: neither variable references whose names are not enclosed in
{...}
(such as$varName
), nor command substitutions ($(...)
and legacy syntax`...`
), nor arithmetic substitutions ($((...))
and legacy syntax$[...]
).To treat a
$
as a literal,\
-escape it; e.g.:\${HOME}
Note that input is only accepted via stdin.
Example:
Function source code:
The function assumes that no
0x1
,0x2
,0x3
, and0x4
control characters are present in the input, because those chars. are used internally - since the function processes text, that should be a safe assumption.我建议使用类似 Sigil 的东西:
https://github.com/gliderlabs/sigil
它被编译为单个二进制文件,因此非常简单安装在系统上。
然后你可以做一个简单的一行,如下所示:
这比 eval 更安全,并且比使用正则表达式或 sed 更容易
I would suggest using something like Sigil:
https://github.com/gliderlabs/sigil
It is compiled to a single binary, so it's extremely easy to install on systems.
Then you can do a simple one-liner like the following:
This is much safer than
eval
and easier then using regex orsed
这是一种让 shell 为您进行替换的方法,就好像文件的内容是在双引号之间键入的一样。
使用带有内容的 template.txt 示例:
以下行将导致 shell 插入 template.txt 的内容并将结果写入标准输出。
说明:
i
和word
作为环境变量传递给sh
的执行。sh
执行传递给它的字符串的内容。echo "
' + "$(cat template.txt)
" + '"
'"
, "$(cat template.txt)
" 成为cat template.txt
的输出。sh -c 执行的命令
变为:echo "数字是 ${i}\n单词是 ${word}"
,i
和word
是指定的环境变量。Here is a way to get the shell to do the substitution for you, as if the contents of the file were instead typed between double quotes.
Using the example of template.txt with contents:
The following line will cause the shell to interpolate the contents of template.txt and write the result to standard out.
Explanation:
i
andword
are passed as environment variables scopped to the execution ofsh
.sh
executes the contents of the string it is passed.echo "
' + "$(cat template.txt)
" + '"
'"
, "$(cat template.txt)
" becomes the output ofcat template.txt
.sh -c
becomes:echo "The number is ${i}\nThe word is ${word}"
,i
andword
are the specified environment variables.如果您愿意使用 Perl,这将是我的建议。 尽管可能有一些 sed 和/或 AWK 专家可能知道如何更轻松地做到这一点。 如果您有一个更复杂的映射,不仅仅是 dbName 来替换,您可以很容易地扩展它,但此时您也可以将其放入标准 Perl 脚本中。
一个简短的 Perl 脚本,用于执行稍微复杂的操作(处理多个键):
如果将上述脚本命名为替换脚本,则可以按如下方式使用它:
If you are open to using Perl, that would be my suggestion. Although there are probably some sed and/or AWK experts that probably know how to do this much easier. If you have a more complex mapping with more than just dbName for your replacements you could extend this pretty easily, but you might just as well put it into a standard Perl script at that point.
A short Perl script to do something slightly more complicated (handle multiple keys):
If you name the above script as replace-script, it could then be used as follows:
文件.tpl:
脚本.sh:
file.tpl:
script.sh:
我在想知道同样的事情时发现了这个线程。 这启发了我(小心反引号)
I found this thread while wondering the same thing. It inspired me to this (careful with the backticks)
这里有很多选择,但我想我会把我的扔到堆上。 它是基于 Perl 的,仅针对 ${...} 形式的变量,将要处理的文件作为参数并在 stdout 上输出转换后的文件:
当然,我不是一个真正的 Perl 人,所以很容易一个致命的缺陷(不过对我有用)。
Lots of choices here, but figured I'd toss mine on the heap. It is perl based, only targets variables of the form ${...}, takes the file to process as an argument and outputs the converted file on stdout:
Of course I'm not really a perl person, so there could easily be a fatal flaw (works for me though).
如果您可以控制配置文件格式,则可以在 bash 本身中完成。 您只需要获取(“.”)配置文件而不是对其进行 subshell。 这确保了变量是在当前 shell 的上下文中创建的(并继续存在),而不是在子 shell 中创建(当子 shell 退出时,变量会消失)。
如果您的配置文件不能是 shell 脚本,您可以在执行之前“编译”它(编译取决于您的输入格式)。
在你的具体情况下,你可以使用类似的东西:
然后将 go.bash 的输出通过管道传输到 MySQL 中,瞧,希望你不会破坏你的数据库:-)。
It can be done in bash itself if you have control of the configuration file format. You just need to source (".") the configuration file rather than subshell it. That ensures the variables are created in the context of the current shell (and continue to exist) rather than the subshell (where the variable disappear when the subshell exits).
If your config file cannot be a shell script, you can just 'compile' it before executing thus (the compilation depends on your input format).
In your specific case, you could use something like:
Then pipe the output of go.bash into MySQL and voila, hopefully you won't destroy your database :-).
对可能的多个文件进行适当的 Perl 编辑,并进行备份。
In place perl editing of potentially multiple files, with backups.
对我来说,这是最简单、最强大的解决方案,您甚至可以使用相同的命令包含其他模板
eval echo "$(:
嵌套模板示例
${VARIABLE_NAME}
或$VARIABLE_NAME
template.txt
nested-template.txt
template.source
To me this is the easiest and most powerful solution, you can even include other templates using the same command
eval echo "$(<template.txt)
:Example with nested template
${VARIABLE_NAME}
or$VARIABLE_NAME
template.txt
nested-template.txt
template.source
我创建了一个名为
shtpl
的 shell 模板脚本。 我的shtpl
使用类似 jinja 的语法,现在我经常使用 ansible,我对此非常熟悉:有关我的 github
I created a shell templating script named
shtpl
. Myshtpl
uses a jinja-like syntax which, now that I use ansible a lot, I'm pretty familiar with:More info on my github
使用
envsubst
请不要使用其他任何东西(即不要
eval
)简单用法:
使用占位符创建模板 (
template.txt
) :安全地替换占位符变量。 将模板提供给
envsubst
的标准输入。请注意,该命令
envsubst < 模板.txt> template.txt
不起作用。 重定向将在读取输出文件之前将其清零。Use
envsubst
Please don't use anything else (ie. don't
eval
)Simple usage:
Create template with placeholder (
template.txt
):To replace placeholder variables SAFELY. Feed the template to stdin of
envsubst
.Note, that command
envsubst < template.txt > template.txt
wont work. Redirection will zero the output file before reading it.