Bash:传递包含多个变量的变量

时间:2018-01-31 16:44:13

标签: bash

这是我的(不工作)设置:

one.sh:

#!/bin/bash -x
MYFLAGS="FLAG=foo"
echo ${MYFLAGS} | ${MYFLAGS} ./two.sh

two.sh:

#!/bin/bash -x
echo $FLAG

输出:

>> one.sh
+ MYFLAGS=FLAG=foo
+ echo FLAG=foo
+ FLAG=foo ./two.sh
./one.sh: line 5: FLAG=foo: command not found

如何将列表(在此casse中只包含一个元素)传递给第二个脚本two.sh?我知道,我可以使用export FLAG使其可用,但我想避免这种情况。

1 个答案:

答案 0 :(得分:3)

解释问题

Shell变量可以包含任意C字符串,因此可以包含除NUL之外的任何字符。因此,您可能放在包含多个其他变量的变量中的任何字符也可能是有效值,因此用作通用分隔符是不安全的。

有一些相当简单的方法可以绕过这个:

  • 在值旁边传递显式长度,并根据它们拆分字符串。
  • 以限制数据中可能出现的字符的方式对值进行编码,例如在字符集中创建开放空间以放置分隔符。

一些更明显的编码方法需要在解码时使用eval。这incurs security risks,因此不赞成。 Workarounds to read eval-style data formats存在,但有些存在重大错误/限制(xargs解析bash的字符串文字格式的子集,但不解析完整集。)

选择以下方法以允许表示所有可能的值,并避免任何安全问题。

通过管道传递任意变量

发出NUL分隔的key=value对流(请注意,您无法将其保存在单个变量中 - 因为NUL终止了值并且文字NUL无法识别存储在字符串中 - 但您可以将其传递给文件描述符):

emit_variables() {
  local var
  for var; do
    printf '%q=%s\0' "${var}" "${!var}"
  done
}

消费它:

read_variables() {
  local varspec
  while IFS= read -r -d '' varspec; do
    name=${varspec%%=*}
    value=${varspec#*=}
    printf -v "$name" '%s' "$value"
  done
}

因此:

# make both these functions available through the environment
export -f emit_variables read_variables

foo=$'bar\nbaz' bar='baz=qux'
emit_variables foo bar | bash -c 'read_variables; declare -p foo bar'

...将正确发出:

declare -- foo="bar
baz"
declare -- bar="baz=qux"

扩展以上使用环境

将内容存储在变量中需要以不会干扰NUL的方式转义数据。例如:

export variable_state=$(emit_variables foo bar | openssl enc -base64)

......而且,这是你的消费者:

read_variables < <(openssl enc -base64 -d <<<"$variable_state")