【问题标题】:Zsh export ignoring quotes and backslashesZsh 导出忽略引号和反斜杠
【发布时间】:2021-08-17 17:42:09
【问题描述】:

我有一个 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 正确处理这个问题?

【问题讨论】:

    标签: shell environment-variables zsh


    【解决方案1】:

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

    export ${(f)"$(./produce.sh)"}
    

    发生了什么

    produce.sh 的输出:

    • 键值对。
    • 每个 kv 对都在自己的线路上。
    • 键与值之间用=分隔。
    • 语法类似于 shell,但不完全是 shell 语法,所以,
    • 值中允许使用空格和一些其他 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.

    【讨论】:

    • 我不完全理解语法,但这就是它的作用。谢谢!
    • @mattbasta :参见man zshexpn,PARAMETER EXPANSION 部分,其中描述了 f 标志。
    • @mattbasta - 我添加了一个解释尝试。
    【解决方案2】:
    FOO=split value
    

    不是否将变量设置为包含空格的值。它临时将FOO 设置为split,并在设置了FOO 的环境中运行命令value。整体效果类似于

    (export FOO=split; value)
    

    你可以尝试一下

    FOO=split printenv
    

    它将运行printenv 并在其输出中显示FOO 的值。

    要将变量设置为包含空格的值,您需要对空格进行转义,例如使用

    FOO=split\ value
    

    或使用引号。

    要处理这个文件,你可以使用eval:

    eval export $(./produce.sh)
    

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

    或者,您可以修改 producer.sh 以在每行前面生成 export 前缀,然后只做一个

    eval $(./produce.sh)
    

    【讨论】:

    • “要将变量设置为包含空格的值,您需要转义空格,例如使用”这正是我在问题中描述的(包括反斜杠和引号)和结果是我的程序分别显示os.environ['FOO'] == 'split\\' 和os.environ['FOO'] == '"split'。
    • @mattbasta :相应地扩展了我的答案。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2017-01-10
    • 1970-01-01
    • 1970-01-01
    • 2019-12-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多