bash 如何替换文本文件中的 ${} 占位符?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/415677/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How to replace ${} placeholders in a text file?
提问by Dana the Sane
I want to pipe the output of a "template" file into MySQL, the file having variables like ${dbName}
interspersed. What is the command line utility to replace these instances and dump the output to standard output?
我想将“模板”文件的输出通过管道传输到 MySQL,该文件中${dbName}
散布着一些变量。替换这些实例并将输出转储到标准输出的命令行实用程序是什么?
回答by user
回答by plockc
Update
更新
Here is a solution from yottatsaon a similar question that only does replacement for variables like $VAR or ${VAR}, and is a brief one-liner
这是yottatsa对类似问题的解决方案,该解决方案仅替换 $VAR 或 ${VAR} 等变量,并且是一个简短的单行
i=32 word=foo envsubst < template.txt
Of course if iand wordare in your environment, then it is just
当然,如果i和word在您的环境中,那么它只是
envsubst < template.txt
On my Mac it looks like it was installed as part of gettextand from MacGPG2
在我的 Mac 上,它看起来像是作为gettext和MacGPG2 的一部分安装的
Old Answer
旧答案
Here is an improvement to the solution from mogsieon a similar question, my solution does not require you to escale double quotes, mogsie's does, but his is a one liner!
这是对mogsie对类似问题的解决方案的改进,我的解决方案不需要您对双引号进行缩放,mogsie 的需要,但他的解决方案是单行的!
eval "cat <<EOF
$(<template.txt)
EOF
" 2> /dev/null
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 isan escape character here, but you don't have to worry that the parsing has a bug, and it does multiple lines just fine.
这两种解决方案的强大之处在于,您只能获得一些通常不会出现的 shell 扩展类型 $((...))、`...` 和 $(...),尽管反斜杠是一个在这里转义字符,但您不必担心解析有错误,并且它可以执行多行。
回答by gnud
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):
使用/bin/sh
. 创建一个设置变量的小 shell 脚本,然后使用 shell 本身解析模板。像这样(编辑以正确处理换行符):
File template.txt:
文件模板.txt:
the number is ${i}
the word is ${word}
File script.sh:
文件脚本.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"
Output:
输出:
#sh script.sh
the number is 1
the word is dog
回答by Dana the Sane
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:
考虑到最近的兴趣,我又在考虑这个问题,我认为我最初想到的工具是m4
autotools 的宏处理器。因此,不是我最初指定的变量,而是使用:
$echo 'I am a DBNAME' | m4 -DDBNAME="database name"
回答by Dana the Sane
template.txt
模板.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=
declare file_input=
declare file_output=
source $file_data
eval "echo \"$(< $file_input)\"" > $file_output
./parser.sh data.sh template.txt parsed_file.txt
./parser.sh data.sh template.txt parsed_file.txt
parsed_file.txt
parsed_file.txt
Variable 1 value: value 1
Variable 2 value: value 2
回答by mklement0
Here's a robust Bash functionthat - despite using eval
- should be safe to use.
这是一个强大的 Bash 函数,尽管使用了它,但使用起来eval
应该是安全的。
All ${varName}
variable references in the input text are expanded based on the calling shell's variables.
${varName}
输入文本中的所有变量引用都基于调用 shell 的变量进行扩展。
Nothing elseis expanded: neither variable references whose names are notenclosed in {...}
(such as $varName
), nor command substitutions ($(...)
and legacy syntax `...`
), nor arithmetic substitutions ($((...))
and legacy syntax $[...]
).
没有其他扩展:名称未包含在{...}
(例如$varName
)中的变量引用、命令替换($(...)
和遗留语法`...`
)、算术替换($((...))
和遗留语法$[...]
)。
To treat a $
as a literal, \
-escape it; e.g.:\${HOME}
要将 a$
视为文字,请\
-escape 它;例如:\${HOME}
Note that input is only accepted via stdin.
请注意,输入只能通过stdin接受。
Example:
例子:
$ expandVarsStrict <<<'$HOME is "${HOME}"; `date` and $(ls)' # only ${HOME} is expanded
$HOME is "/Users/jdoe"; `date` and $(ls)
Function source code:
函数源代码:
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 '`([$' '')
# ... then selectively reenable ${ references
lineEscaped=${lineEscaped//$''{/${}
# Finally, escape embedded double quotes to preserve them.
lineEscaped=${lineEscaped//\"/\\"}
eval "printf '%s\n' \"$lineEscaped\"" | tr '' '`([$'
done
}
The function assumes that no 0x1
, 0x2
, 0x3
, and 0x4
control characters are present in the input, because those chars. are used internally - since the function processes text, that should be a safe assumption.
该函数假定输入中不存在0x1
、0x2
、0x3
和0x4
控制字符,因为这些字符。在内部使用 - 因为函数处理text,这应该是一个安全的假设。
回答by Thomas
here's my solution with perl based on former answer, replaces environment variables:
这是我根据以前的答案使用 perl 的解决方案,替换了环境变量:
perl -p -e 's/$\{(\w+)\}/(exists $ENV{}?$ENV{}:"missing variable ")/eg' < infile > outfile
回答by neu242
Create rendertemplate.sh
:
创建rendertemplate.sh
:
#!/usr/bin/env bash
eval "echo \"$(cat )\""
And template.tmpl
:
并且template.tmpl
:
Hello, ${WORLD}
Goodbye, ${CHEESE}
Render the template:
渲染模板:
$ export WORLD=Foo
$ CHEESE=Bar ./rendertemplate.sh template.tmpl
Hello, Foo
Goodbye, Bar
回答by Beau Simensen
If you are open to using Perl, that would be my suggestion. Although there are probably some sedand/or AWKexperts 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.
如果您愿意使用Perl,那将是我的建议。尽管可能有一些sed和/或AWK专家可能知道如何更容易地做到这一点。如果您有一个更复杂的映射,而不仅仅是 dbName 用于替换,您可以很容易地扩展它,但此时您最好将其放入标准 Perl 脚本中。
perl -p -e 's/$\{dbName\}/testdb/s' yourfile | mysql
A short Perl script to do something slightly more complicated (handle multiple keys):
一个简短的 Perl 脚本来做一些稍微复杂的事情(处理多个键):
#!/usr/bin/env perl
my %replace = ( 'dbName' => 'testdb', 'somethingElse' => 'fooBar' );
undef $/;
my $buf = <STDIN>;
$buf =~ s/$\{$_\}/$replace{$_}/g for keys %replace;
print $buf;
If you name the above script as replace-script, it could then be used as follows:
如果您将上述脚本命名为 replace-script,则可以按如下方式使用它:
replace-script < yourfile | mysql
回答by user976433
file.tpl:
文件.tpl:
The following bash function should only replace ${var1} syntax and ignore
other shell special chars such as `backticks` or $var2 or "double quotes".
If I have missed anything - let me know.
script.sh:
脚本.sh:
template(){
# usage: template file.tpl
while read -r line ; do
line=${line//\"/\\"}
line=${line//\`/\\`}
line=${line//$/\$}
line=${line//\${/${}
eval "echo \"$line\"";
done <
}
var1="*replaced*"
var2="*not replaced*"
template file.tpl > result.txt