Bash 4.4 and 4.3 seem to behave differently with regards to passing variables into subshells or heredocs.
From @CharlesDuffy a simple reproduction:
export var=0; var=1 cat <<<"$(env | grep '^var')"
Bash 4.4 outputs var=0, bash 4.3 outputs 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:
TZ=Europe/London
timezone=Asia/Tokyo
14:52
22:52
TZOUTER 22-52
TZINNER 22-52
Bash 4.4 (Ubuntu 17.04) gives:
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).
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.
From the detailed changelog entry from 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. Sinceexpanding_redironly controls access to the temporary environment for variable lookup and binding, we can turn it off in the subshell
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.
This changed because bash 4.3 incorrectly applied the precommand modifier to the evaluation of the command substitution in the here document. 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. 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. Some related bugs were fixed in 4.3, but others persisted.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With