序列化环境变量的子集

时间:2017-08-16 11:31:48

标签: bash sh busybox

我试图导出一些环境变量供TomCat进程使用。

有几种方法可以做到这一点(我知道如何解决整体问题),但它告诉我,我不知道如何执行这个特定的shell任务

Tomcat建议您应该"$CATALINA_HOME/bin/setenv.sh"导出所有环境自定义。

这整个事情都会塞进Docker容器中,所以唯一的参数可以通过Docker env变量(让我们假设这个任务我不想使用卷挂载或创建{在构建过程中{1}}。

首先,观察setenv.sh可用于将环境传递到容器中:

docker run -e

如果我们想将该env的所有复制到 docker run -eMY_VAR=SUP alpine env PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin HOSTNAME=a528b6fc264b MY_VAR=SUP no_proxy=*.local, 169.254/16 HOME=/root ,它就像以下一样简单:

setenv.sh

但是复制所有内容在某种程度上违背了SETENV="/usr/local/tomcat/bin/setenv.sh" echo '#!/bin/sh' > "$SETENV" echo 'export -p' >> "$SETENV" env >> "$SETENV" 的要点 - 这就是为了给你的tomcat进程一个 clean 环境,只有有意的自定义。

因此,我们可以就&#34的约定达成一致;其中env vars是我们想要传递给setenv.sh"的那些。所有内容都以setenv.sh为前缀。

现在我们遇到了一个有趣的shell问题。

MY_

这让我们非常接近。输出如下:

env | grep '^MY_' | sed 's/^MY_/EXPORT /'

所以,我们已经从 docker run -e MY_VAR=hey alpine sh -c "env | grep '^MY_' | sed 's/^MY_/EXPORT /'" EXPORT VAR=hey 命令中选择了:只有前缀为env的env vars。我们可以将该输出重定向到MY_

为什么我说"非常接近"?看起来我们已经完成了,对吧?

尝试尺寸:

setenv.sh

该脚本仅适用于一小部分可能性。即我们只设法导出多行字符串的第一行。

为方便起见:多行字符串的env输出如下所示:

 docker run -e MY_VAR='multi                                                    
quote> line  
quote> string' alpine sh -c "env | grep '^MY_' | sed 's/^MY_/EXPORT /'"
EXPORT VAR=multi

我犹豫试图用awk解决这个问题;可能还有其他字符串逃避并发症,我没有考虑过。

我想知道是否有一个更好的方法来选择&序列化导出环境的子集?

编辑:我故意将此标记为 docker run -e MY_VAR='multi line string' alpine env PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin HOSTNAME=0d0afaac6bec MY_VAR=multi line string no_proxy=*.local, 169.254/16 HOME=/root 问题,而我的意图是提出bash问题。具体来说,我的目的是获得一些除了高山码头图像附带的东西之外没有依赖性的东西。即BusyBox shshsedgrepawk

我保留了env代码,以免在这是bash唯一的问题时惩罚提交的初始答案。

但我会优先考虑一个bash兼容的答案,特别是那个只适用于BusyBox UNIX工具的答案。

4 个答案:

答案 0 :(得分:1)

alpine图片未附带bash

您可以使用此脚本提取所有MY_*变量,包括换行变量:

docker run -e MY_FOO=bar -e MY_VAR="multi' export MY_INJECTED='val" -e MY_VAR2=$'multi
0MY_line=val
string' alpine sh -c "awk -v RS='\06' -F= '/^MY_/{k=\$1; sub(/^[^=]+=/, \"\"); 
gsub(/\047/, \"\047\\\\\\047\047\"); printf \"export %s=\047%s\047\n\", k, \$0
}' /proc/self/environ"

这将输出:

export MY_FOO='bar'
export MY_VAR='multi'\'' export MY_INJECTED='\''val'
export MY_VAR2='multi
0MY_line=val
string'

以下是awk的工作原理:

  • -v RS='\6':将记录分隔符设置为\6也适用于nul字节(假设您的值没有\6
  • -F=:将字段分隔符设置为=
  • /^MY_/:仅处理以MY_
  • 开头的记录
  • 在变量$1
  • 中存储变量名称或k
  • sub
  • =之后使用$0函数获取部分
  • 使用print格式输出,以便可以在$CATALINA_HOME/bin/setenv.sh文件中使用。
  • \047用于打印单引号

答案 1 :(得分:1)

假设GNU grep:

grep --null '^MY_' </proc/self/environ

...将以NUL分隔的形式(完整的换行符)发出环境变量。

同样,如果你有bash:

while IFS= read -r -d '' vardef; do
  [[ $vardef = MY_* ]] && printf '%s\0' "$vardef"
done </proc/self/environ

请注意,如果在同一个shell会话中设置了这些变量,则可能需要创建要更新的/proc/self/environ的子流程:

(while IFS= read -r -d '' vardef; do
   [[ $vardef = MY_* ]] && printf '%s\0' "$vardef"
 done </proc/self/environ)

答案 2 :(得分:1)

所以你需要几件事:

  • 枚举环境变量并选择子集。
  • 对于每个选定的环境变量,发出sh代码,将变量设置为所需的值。

如果要以可以读回的形式导出所有变量,可以使用export -p,但解析它只选择某些变量会更难。使用export -p的一种方法是取消设置其他变量。这仅在没有任何环境变量是只读的情况下有效,但您可以通过运行单独的shell实例(而不是子shell)来解决此问题。

要收集要取消设置的变量列表,您只需获取所有环境变量列表的超集,然后删除要保留的变量。您可以通过过滤env输出轻松完成此操作。我使用简单的grep执行此操作,如果您包含的条件比“以特定前缀开头”更复杂,则可能需要使用更复杂的代码。

由于包含换行符后跟有效变量名称和等号的变量而偶尔出现误报,只会导致在不存在的变量上调用unset。从排除列表中删除所需的变量,因此最终输出将永远不会省略所需的变量。

excluded=$(env | LC_ALL=C sed -n 's/^\([A-Z_a-z][0-9A-Z_a-z]*\)=.*/\1/p' |
           grep -v 'MY_')
sh -c 'unset $1; export -p' sh "$excluded" >setenv.sh

如果export PATH在调用时位于环境中,则Dash会打印额外的PATH(没有值)。如果这让您感到困扰,请将sh -c …更改为(unset PATH; sh -c …)

答案 3 :(得分:0)

怎么样

declare -p ${!MY_*}

declare -p ${!MY_*} | sed -r 's/^declare (-[^ ]*)* MY_/export /'

declare -p ${!MY_*} | sed 's/^declare \(-[^ ]*\)* MY_/export /'

EDIT posix兼容版本:

某些envprintenv接受-0选项可以按\0而不是换行符结束每个输出行。因此

env -0  | perl -ne 'BEGIN{$/="\0";$\="\n";$q="\047"}next unless /^MY_/;chomp;s/$q/$q\\$q$q/;s/=/=$q/;s/$/$q/;print'

工作原理

$/ : input record separator
$\ : output record separator
$q : variable to store single quote (\047) because of surrounding single quotes in command
next : to filter "MY_" variables
chomp : removes the input separator
s/// : quote substitution

编辑:posix shell中perl版本的变体

env -0 | xargs -0 sh -c 'for entry; do [[ $entry = MY_* ]] || continue; printf "%s=\047%s\047\n" "${entry%%=*}" "$(echo "${entry#*=}" | sed '\''s/\x27/\x27\\\x27\x27/g'\'' )"; done' -