所以我有一个疯狂的想法,就是将文档嵌入脚本中(这对我来说不是什么新鲜事物,只是新内容),然后使用sed解析它们。我可以通过用行定界符注释掉一段文本,然后在将字符串打印到stdout时弹出注释哈希(在每一行上)来实现此目的。
以一个示例为例,想象这样一个shell脚本myscript.sh
:
#!/usr/bin/env bash
#---- doc:start ----#
# Hello $User\n
# This is myscript.sh
# ${red}This will be red!${eol}
#---- doc:end ----#
printf "Hello, World!"
我有一个sed脚本,该脚本可以捕获线里程表之间的所有内容,并将其放入多行变量$doc
使用这个变量,我想对任何局部变量(不一定是导出的变量),转义码,术语颜色等进行插值,并且在查看如何执行此操作时,我唯一能找到的答案就是使用eval;这是一个工作示例(在这里使用字符串):
while IFS= read -r line; do
line=$(eval "echo -e \"$line\"");
echo "$line"
done <<< "$doc"; # doc is a multiline variable
但是,如果有人在此文本块中添加$(rm -rf ..)
,则会执行该文本;这种模式似乎允许其他不安全方案。
我研究的另一种方法是使用printf -v line ...
动态分配变量,但是无法成功进行变量替换。
我想在Bash 3.2上下文中实现此目标,而不必安装任何其他工具或实用程序;尽可能使用POSIX,但是Bashism和通用实用程序也可以。 想要在Mac和Ubuntu上都可以使用 。
也许正则表达式可以排除任何看起来像可执行命令(或超级转义可疑字符串)的东西。
答案 0 :(得分:3)
使用GNU gettext包中的envsubst
。
这仅要求您导出应该被替换的变量。以下用法演示了在red
调用期间将常规shell变量eol
和envsubst
临时提升为环境变量:
red="$red" eol="$eol" envsubst <<<'EOF'
...${red}...${eol}...
EOF
答案 1 :(得分:0)
听起来像您真正需要的是模板,而不是变量插入。也就是说,您可以明确地逐个变量地执行此操作,这可能会提供额外的安全性。
#!/usr/bin/env bash
#---- doc:start ----#
# Hello $User\n
# This is myscript.sh
# ${red}This will be red!${eol}
#---- doc:end ----#
# template replacemenmts
red=$'\e[31m'
norm=$'\e[m'
eol=$'\n'
# fetch and trim...
s=$(< $0)
s=${s%%#---- doc:end ----#*}
s=${s##*#---- doc:start ----#}
# do substitutions
s=${s//\$User/$USER}
s=${s//\${red\}/$red}
s=${s//\${eol\}/$eol}
s=${s//\\n/$eol}
printf '%s\n%s' "$s" "$norm"
这避免了使用sed
或其他可能因平台而异的其他东西。 (例如,sed
在GNU,FreeBSD / MacOS和Solaris之间是不同的。)
只需考虑一下here's an example,我就倾向于将文档嵌入bash脚本中。 (是的,我使用sed。:-))