set v (seq 10)
echo 'Before: v = '"$v"
set foobar (for v in $v; echo $v; end)
echo "After: v = $v"
echo 'Set sez:'
set -S v
Output:
Before: v = 1 2 3 4 5 6 7 8 9 10
After: v = 10
Set sez:
$v: not set in local scope
$v: set in global scope, unexported, with 1 elements
$v[1]: length=2 value=|10|
$v: not set in universal scope
Okay, maybe 'correct behaviour' is a little ambiguous here. Maybe the user wants to know the inner value of v?
But here's the real problem:
set v (seq 10); echo 'Before: v = '"$v";function f; set foobar (for v in $v; echo $v; end); end; f; echo "After: v = $v";echo 'Set sez:'; set -S v
In other words, if you set a variable in your shell and then call a function which uses a variable of the same name in a subshell, your variable gets clobbered. That means if you want to ensure your variables stay intact, you cannot use the most convenient short variable names (a,b, ..), since any function might use a subshell that happens to clobber them.
This is subshell specific. 'v' is not clobbered in the following case:
set v (seq 10); echo 'Before: v = '"$v";function f; for v in $v; echo -n "$v "; end; end; f; echo "After: v = $v";echo 'Set sez:'; set -S v
It is not specific to 'for' loops. 'while' loops in a subshell clobber in a different way:
set v (seq 10); echo 'Before: v = '"$v";function f; set foobar (printf %s\n $v | while read v; echo $v; end); echo $foobar; end; f; echo "After: v = $v";echo 'Set sez:'; set -S v
The result of the above is that, instead of v being set to 10, it is set to nothing (ie set -g v)
Two more cases. No loop, just set:
set v (seq 10); echo 'Before: v = '"$v";function f; set foobar (set v (string join '' $v)); end; f; echo "After: v = $v";echo 'Set sez:'; set -S v
(v's value is now 12345678910)
No loop, just set -l
set v (seq 10); echo 'Before: v = '"$v";function f; set foobar (set -l v (string join '' $v)); end; f; echo "After: v = $v";echo 'Set sez:'; set -S v
This final case produces 'correct' results (v is not clobbered)
Expected behaviour:
At least within a function, a subshell should not be able to damage variables in the global scope without explicitly stating that it is intended (set -g). In the cases of for VARNAME and while VARNAME within a subshell, VARNAME should either be set locally to the subshell, or locally to the function.
fish --version: fish, version 3.0.2-2058-gd0edd984d
uname -a: Linux cooler 5.4.6-arch3-1 #1 SMP PREEMPT Tue, 24 Dec 2019 04:36:53 +0000 x86_64 GNU/Linux
$TERM: xterm-256color
Problem occurs in clean fish install: Yes
Output:
Okay, maybe 'correct behaviour' is a little ambiguous here. Maybe the user wants to know the inner value of v?
But here's the real problem:
In other words, if you set a variable in your shell and then call a function which uses a variable of the same name in a subshell, your variable gets clobbered. That means if you want to ensure your variables stay intact, you cannot use the most convenient short variable names (a,b, ..), since any function might use a subshell that happens to clobber them.
This is subshell specific. 'v' is not clobbered in the following case:
It is not specific to 'for' loops. 'while' loops in a subshell clobber in a different way:
The result of the above is that, instead of v being set to 10, it is set to nothing (ie
set -g v)Two more cases. No loop, just set:
(v's value is now
12345678910)No loop, just set -l
This final case produces 'correct' results (v is not clobbered)
Expected behaviour:
At least within a function, a subshell should not be able to damage variables in the global scope without explicitly stating that it is intended (
set -g). In the cases offor VARNAMEandwhile VARNAMEwithin a subshell, VARNAME should either be set locally to the subshell, or locally to the function.fish --version: fish, version 3.0.2-2058-gd0edd984duname -a: Linux cooler 5.4.6-arch3-1 #1 SMP PREEMPT Tue, 24 Dec 2019 04:36:53 +0000 x86_64 GNU/Linux$TERM: xterm-256colorProblem occurs in clean fish install: Yes