我想将"模板"文件的输出传递给MySQL,该文件包含${dbName}
散布的变量.什么是命令行实用程序来替换这些实例并将输出转储到标准输出?
塞德!
给出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
调用.
以下是来自yottatsa的类似问题的解决方案,该问题仅替换$ VAR或$ {VAR}等变量,并且是一个简短的单行
i=32 word=foo envsubst < template.txt
当然,如果我和你的话语在你的环境中,那么它就是
envsubst < template.txt
在我的Mac上,它看起来像是作为gettext和MacGPG2的一部分安装的
这是对mogsie在类似问题上的解决方案的改进,我的解决方案并不要求你使用双引号,mogsie's,但他是一个单行!
eval "cat </dev/null
这两个解决方案的优势在于你只能得到几种类型的shell扩展,这些扩展通常不会出现$((...)),`...`和$(...),尽管反斜杠是一个转义字符在这里,但你不必担心解析有一个错误,它做多行就好了.
使用/bin/sh
.创建一个设置变量的小shell脚本,然后使用shell本身解析模板.像这样(编辑以正确处理换行):
the number is ${i} the word is ${word}
#!/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
鉴于最近的兴趣,我再次考虑这个问题,我认为我最初想到的工具是m4
autotools的宏处理器.因此,不是我最初指定的变量,而是使用:
$echo 'I am a DBNAME' | m4 -DDBNAME="database name"
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
这是我基于前一个答案的perl解决方案,替换环境变量:
perl -p -e 's/\$\{(\w+)\}/(exists $ENV{$1}?$ENV{$1}:"missing variable $1")/eg' < infile > outfile
这是一个强大的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
控制字符存在于输入,因为那些字符.在内部使用 - 因为函数处理文本,这应该是一个安全的假设.
创建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
如果您愿意使用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