Zsh 导出忽略引号和反斜杠

Zsh export ignoring quotes and backslashes

我有一个 shell 脚本(我们称之为 produce.sh),它以下列形式输出数据,但不将其保存到文件中:

FOO=value
BAR=value2
ZAP=value3

我想在 shell 脚本中将这些值用作环境变量。我目前正在使用以下 shell 代码执行此操作:

export $(./produce.sh)

这很好用,除非 = 右边的值包含空格。例如:

FOO=split value

我在 produce.sh 中尝试了两种不同的方法:

  1. 将值用引号引起来 (FOO="split value")
  2. 使用反斜杠转义空格 (FOO=split\ value)

这两个都不起作用:如果我检查环境变量,FOO 在第一个示例中包含 "split,在第二个示例中包含 split\

我怎样才能 export 正确处理这个问题?

zsh 中的 f 参数扩展标志将在换行符上拆分输入,因此这应该处理带有 whitespace:

的输入值
export ${(f)"$(./produce.sh)"}

发生了什么事

produce.sh的输出:

  • 键值对。
  • 每个 kv 对在其自己的行上。
  • key 和 value 被 = 隔开。
  • 语法类似于 shell,但不完全是 shell 语法,因此,
  • white space 和一些其他 shell 的特殊字符在值中是允许的。

替换部分:

  • produce.sh :生成键值输出,例如:N=V1\nP=V 2\n.
  • $(...) :命令替换。它被替换为输出,减去尾随换行符:N=V1\nP=V 2.
  • "..." :引号确保先前的结果被视为下一步的单个术语。
  • ${(f)...} :将该单个项扩展为多个标量值,由于 (f) 标志而在换行符处拆分。结果实际上是 'N=V1' 'P=V 2'.
  • export :分配和导出每个参数,作用类似于 export 'N=V1' 'P=V 2'.

另一种选择

下面的替换添加了一些其他神秘的 zsh-isms 来创建关联数组。这避免了向消费 shell 中添加任意变量 环境:

% ./s2.sh
A=A
B=
C=C C
% typeset -A vals=("${(@s:=:)${(f)"$(./s2.sh)"}}")
% print ${vals[A]}
A
% print ${vals[C]}
C C

一个小的权衡 - 如果值包含等号,这将不起作用,例如 D=D=D.

FOO=split value

是否将变量设置为包含space的值。它临时将 FOO 设置为 split 并且 运行 在已设置 FOO 的环境中执行命令 value。整体效果类似

(export FOO=split; value)

您可以通过

来试验一下
FOO=split printenv

这将 运行 printenv 并在其输出中显示 FOO.

的值

要将变量设置为包含 space 的值,您需要转义 space,例如

FOO=split\ value

或使用引号。

要处理此文件,您可以使用 eval:

eval export $(./produce.sh)

当然,只有当您完全控制 produce.sh 正在写入标准输出的内容时才应该这样做(即不要让任何受污染的数据潜入),因为 eval 是一种潜在的安全措施孔.

或者,您可以修改 produce.sh 以在每行前面生成 export 前缀,然后只执行

eval $(./produce.sh)