简体   繁体   English

bash 4.4没有将变量传递给子shell

[英]bash 4.4 not passing variables to sub-shell

Bash 4.4 and 4.3 seem to behave differently with regards to passing variables into subshells or heredocs. Bash 4.4和4.3在将变量传递到subshel​​l或heredocs方面似乎表现不同。

From @CharlesDuffy a simple reproduction: 来自@CharlesDuffy的简单复制:

export var=0; var=1 cat <<<"$(env | grep '^var')"

Bash 4.4 outputs var=0 , bash 4.3 outputs var=1 . Bash 4.4输出var=0 ,bash 4.3输出var=1

My original script for reproducing the problem: 我的原始脚本用于重现该问题:

TZ=Europe/London
timezone=Asia/Tokyo
echo TZ=$TZ
echo timezone=$timezone

date +%H:%M
TZ=$timezone date +%H:%M

IFS=':' TZ=$timezone read hour minute <<EOF
        $(date +%H:%M)
EOF
echo TZOUTER $hour-$minute

IFS=':' read hour minute <<EOF
        $(TZ=$timezone date +%H:%M)
EOF
echo TZINNER $hour-$minute

Bash 4.3 (Ubuntu 16.04) gives: Bash 4.3(Ubuntu 16.04)提供:

TZ=Europe/London
timezone=Asia/Tokyo
14:52
22:52
TZOUTER 22-52
TZINNER 22-52

Bash 4.4 (Ubuntu 17.04) gives: Bash 4.4(Ubuntu 17.04)提供:

TZ=Europe/London
timezone=Asia/Tokyo
13:53
22:53
TZOUTER 13-53
TZINNER 22-53

(On bash 4.3 both the inner and outer approaches give the same time, on bash 4.4 the TZOUTER gives the original TZ value). (在bash 4.3上,内部和外部方法给出的时间相同,在bash 4.4上,TZOUTER给出原始TZ值)。

Does anyone know why this changed? 有谁知道为什么这改变了? I've looked over https://lists.gnu.org/archive/html/info-gnu/2016-09/msg00008.html but I can't work out which change caused the alteration to behavior. 我查看了https://lists.gnu.org/archive/html/info-gnu/2016-09/msg00008.html,但我无法弄清楚是哪个更改导致了行为的改变。

From the detailed changelog entry from 2014-12-3: 从2014-12-3的详细变更日志条目中:

subst.c

  • command_substitute : if running command substitution as part of expanding a redirection (expanding_redir == 1) , flush any temporary environment we've inherited as part of this command, since we are not supposed to have access to the temporary environment. command_substitute :如果在扩展重定向的过程中运行命令替换(expanding_redir == 1) ,请刷新我们作为该命令一部分继承的任何临时环境,因为我们不应访问该临时环境。 Since expanding_redir only controls access to the temporary environment for variable lookup and binding, we can turn it off in the subshell 由于expanding_redir仅控制对临时环境的访问以进行变量查找和绑定,因此我们可以在子shell中将其关闭

Specifically, the following new code is added: 具体来说,添加了以下新代码:

  if (expanding_redir)
    {
      flush_temporary_env ();
      expanding_redir = 0;
    }

...which simply removes all contents of the temporary_env hash table, preventing temporary environment variables from being inappropriately expanded when merge_temporary_env() is invoked in execute_simple_command() during redirection-related expansions. ......它只是删除的所有内容temporary_env哈希表,防止当被不适当地扩大临时环境变量merge_temporary_env()被调用中execute_simple_command()中重定向相关的扩展。

This changed because bash 4.3 incorrectly applied the precommand modifier to the evaluation of the command substitution in the here document. 之所以更改,是因为bash 4.3在本文档中错误地将precommand修饰符应用于命令替换的评估。 In

IFS=':' TZ=$timezone read hour minute <<EOF
$(date +%H:%M)
EOF

both the change to IFS and to TZ should only be visible to the read command itself, not the date command. IFSTZ的更改应该read命令本身可见,而对date命令不可见。 The above should work identically to 上面的应该与

dateStr=$(date +%H:%M)
IFS=':' TZ=$timezone read hour minute <<EOF
$dateStr
EOF

This bug was fixed in bash 4.4, I suspect as part of a general audit of the code related to the evaluation of here documents and here strings. 此错误已在bash 4.4中修复,我怀疑这是与此处文档和此处字符串的评估有关的代码的常规审核的一部分。 Some related bugs were fixed in 4.3, but others persisted. 一些相关的错误已在4.3中修复,但其他错误仍然存​​在。

The difference between the two environments may be that TZ is exported or not 两种环境之间的差异可能在于是否导出了TZ

(
    export TZ
    IFS=':' TZ=$timezone read hour minute <<EOF
        $(date +%H:%M)
EOF
    echo TZOUTER $hour-$minute
)

(
    IFS=':' TZ=$timezone read hour minute <<EOF
        $(date +%H:%M)
EOF
    echo TZOUTER $hour-$minute
)

EDIT To avoid variable expansion inside here-doc add single quotes around EOF 编辑为了避免在这里文档内部进行变量扩展,请在EOF周围添加单引号

IFS=':' TZ=$timezone read hour minute <<'EOF'
    $(date +%H:%M)
EOF

But here it's expected to expand shell command, so the clearest 但是这里需要扩展shell命令,所以最清晰

(
    TZ=$timezone 
    IFS=':' read hour minute <<EOF
        $(date +%H:%M)
EOF
)

the other is more ambiguous because parameter applies to read command but it is not clear if it should apply to heredoc substitution 另一个比较不明确,因为参数适用于read命令,但尚不清楚是否应将其应用于heredoc替换

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM