我想将一个包含像
${dbName}
这样的变量的“模板”文件的输出导入到MySQL中。有什么命令行工具可以替换这些实例并将输出转储到标准输出?输入文件被认为是安全的,但可能存在错误的替换定义。执行替换应避免执行意外的代码执行。${dbName}
这样的变量的“模板”文件的输出导入到MySQL中。有什么命令行工具可以替换这些实例并将输出转储到标准输出?输入文件被认为是安全的,但可能存在错误的替换定义。执行替换应避免执行意外的代码执行。i=32 word=foo envsubst < template.txt
envsubst < template.txt
这是对mogsie在类似问题上提出的解决方案的改进,我的解决方案不需要你转义双引号,而mogsie的解决方案是一行代码!
eval "cat <<EOF
$(<template.txt)
EOF
" 2> /dev/null
Sed!
给定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
调用。
cat
命令。你只需要运行以下命令:sed -e "s/\${i}/1/" -e "s/\${word}/dog/" template.text
,它会将模板文件中的 ${i}
替换为 1
,${word}
替换为 dog
。 - HardlyKnowEmsed
会期望一个已转义的文本,这很麻烦。 - jpbochised -e "s/\${i}/1/" -e "s/\${word}/dog/" template.text | tee newFile
。 - rubiktubik请使用/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
read
命令会修剪每行开头和结尾的空格并“吃掉”\
字符,(c)只有在完全信任或控制输入时才使用此功能,因为嵌入在输入中的命令替换(\
...` 或
$(...))允许由于使用
eval 执行任意命令。最后,
echo` 有很小的机会将一行的开头误认为是其命令行选项之一。 - mklement0最近因为大家的兴趣,我又再次考虑了这个问题,并且我认为我最初想到的工具是m4
,这是用于Autotools的宏处理器。因此,您可以使用我最初指定的变量来代替:
$echo 'I am a DBNAME' | m4 -DDBNAME="database name"
envsubst
。 m4
是一个很棒的工具,但它是一个完整的预处理器,具有更多功能和复杂性,如果您只想替换一些变量,则可能不需要它。 - imiric创建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
$(rm -rf ~)
,那么你就会将其作为代码运行。 - Charles Duffyeval "echo \"$(cat $1)\""
运行良好! - dev devvtemplate.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
parsed_file.txt
Variable 1 value: value 1
Variable 2 value: value 2
\
…`或$(...)
)会由于使用eval
而允许执行任意命令,并且由于使用source
而直接执行Shell代码。
此外,输入中的双引号会被静默丢弃,而echo
可能会将一行开头误认为是其命令行选项之一。 - mklement0$ 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
,它也非常安全可靠。 - anubhava"
!) - WBAR${FOO:-bar}
提供默认值,或者仅在设置了某些内容时输出${HOME+Home is ${HOME}}
。我猜测通过一点扩展,它还可以返回缺失变量${FOO?Foo is missing}
的退出代码,但目前尚未实现。如果需要,https://www.tldp.org/LDP/abs/html/parameter-substitution.html上有这些内容的列表。 - Stuart Moore这是我的解决方案,基于以前的答案,使用 Perl 替换环境变量:
perl -p -e 's/\$\{(\w+)\}/(exists $ENV{$1}?$ENV{$1}:"missing variable $1")/eg' < infile > outfile
cat my-file.conf.template | sigil -p $(env) > my-file.conf
这比使用eval
更安全,比使用正则表达式或sed
更容易。
cat
命令,而是使用 <my-file.conf.template
命令,这样可以给 sigil
一个真正的文件句柄,而不是一个 FIFO。 - Charles Duffy以下是一种让shell为您执行替换的方法,就好像文件的内容被输入在双引号之间一样。
以template.txt为例,其内容如下:
The number is ${i}
The word is ${word}
i='1' word='dog' sh -c 'echo "'"$(cat template.txt)"'"'
解释:
i
和 word
作为环境变量传递给执行 sh
命令。sh
执行传递给它的字符串内容。echo "
' + "$(cat template.txt)
" + '"
'"
之间,"$(cat template.txt)
" 变成了 cat template.txt
命令的输出结果。sh -c
执行的命令变成了:
echo "The number is ${i}\nThe word is ${word}"
,i
和 word
是指定的环境变量。'$(rm -rf ~)'$(rm -rf ~)
这样的内容,在模板文件中的字面引号将与它扩展前添加的引号匹配。 - Charles Duffy${varname}
,而不是其他更高安全风险的扩展。 - Charles Duffy"
,否则它将与shell中的"
匹配。您可以传递'echo "'"$(sed 's/"/\\"/g' template)"'"'
而不是'echo "'"$(cat template.txt)"'"'
到sh -c来解决这个问题(但现在我们又回到了正则表达式的hack)。我需要再考虑一下,但可能仍然有方法欺骗它做一些不直观的事情。 - Apriori$(...)
不是原问题的重点;相反,当我发现这个问题时,我正在寻找一个解决方案,然后提供了一个答案。 老实说,我对代码执行部分也没有用处,但是用正则表达式替换变量很糟糕,并且在其他方面不会像shell变量那样运行,因此我认为让shell执行插值的一行代码非常优雅。不幸的是,我不知道调用sh
以使其扩展变量但不执行代码的方法。 - Apriorienv -i
作为前缀,以切断外部环境。 - plockc
envsubst
无法正常工作。 - Toddius Zho