mirror of
https://github.com/fish-shell/fish-shell.git
synced 2024-11-25 08:36:35 +08:00
b7f35f949e
Universal exported variables (created by `set -xU`) used to show up both as universal and global variable in child instances of fish. As a result, when changing an exported universal variable, the new value would only be visible after a new login (or deleting the variable from global scope in each fish instance). Additionally, something like `set -xU EDITOR vim -g` would be imported into the global scope as a single word resulting in failures to execute $EDITOR in fish. We cannot simply give precedence to universal variables, because another process might have exported the same variable. Instead, we only skip importing a variable when it is equivalent to an exported universal variable with the same name. We compare their values after joining with spaces, hence skipping those imports does not change the environment fish passes to its children. Only the representation in fish is changed from `"vim -g"` to `vim -g`. Closes #5258. This eliminates the issue #5348 for universal variables.
478 lines
13 KiB
Fish
478 lines
13 KiB
Fish
# RUN: env XDG_CONFIG_HOME="$(mktemp -d)" FISH=%fish %fish %s
|
|
|
|
# Environment variable tests
|
|
|
|
# Test if variables can be properly set
|
|
|
|
set smurf blue
|
|
|
|
if test $smurf = blue
|
|
echo Test 1 pass
|
|
else
|
|
echo Test 1 fail
|
|
end
|
|
# CHECK: Test 1 pass
|
|
|
|
# Test if variables can be erased
|
|
|
|
set -e smurf
|
|
if set -q smurf
|
|
echo Test 2 fail
|
|
else
|
|
echo Test 2 pass
|
|
end
|
|
# CHECK: Test 2 pass
|
|
|
|
# Test if local variables go out of scope
|
|
|
|
set -e t3
|
|
if true
|
|
set -l t3 bar
|
|
end
|
|
|
|
if set -q t3
|
|
echo Test 3 fail
|
|
else
|
|
echo Test 3 pass
|
|
end
|
|
# CHECK: Test 3 pass
|
|
|
|
# Test if globals can be set in block scope
|
|
|
|
if true
|
|
set -g baz qux
|
|
end
|
|
|
|
if test $baz = qux
|
|
echo Test 4 pass
|
|
else
|
|
echo Test 4 fail
|
|
end
|
|
# CHECK: Test 4 pass
|
|
|
|
|
|
#Test that scope is preserved when setting a new value
|
|
|
|
set t5 a
|
|
|
|
if true
|
|
set t5 b
|
|
end
|
|
|
|
if test $t5 = b
|
|
echo Test 5 pass
|
|
else
|
|
echo Test 5 fail
|
|
end
|
|
# CHECK: Test 5 pass
|
|
|
|
# Test that scope is preserved in double blocks
|
|
|
|
for i in 1
|
|
set t6 $i
|
|
for j in a
|
|
if test $t6$j = 1a
|
|
echo Test 6 pass
|
|
else
|
|
echo Test 6 fail
|
|
end
|
|
end
|
|
end
|
|
# CHECK: Test 6 pass
|
|
|
|
|
|
# Test if variables in for loop blocks do not go out of scope on new laps
|
|
|
|
set res fail
|
|
|
|
set -e t7
|
|
for i in 1 2
|
|
if test $i = 1
|
|
set t7 lala
|
|
else
|
|
if test $t7
|
|
set res pass
|
|
end
|
|
end
|
|
end
|
|
|
|
echo Test 7 $res
|
|
# CHECK: Test 7 pass
|
|
|
|
# Test if variables are properly exported
|
|
|
|
set -e t8
|
|
if true
|
|
set -lx t8 foo
|
|
if test ($FISH -c "echo $t8") = foo
|
|
echo Test 8 pass
|
|
else
|
|
echo Test 8 fail
|
|
end
|
|
end
|
|
# CHECK: Test 8 pass
|
|
|
|
# Test if exported variables go out of scope
|
|
|
|
if $FISH -c "set -q t8; and exit 0; or exit 1"
|
|
echo Test 9 fail
|
|
else
|
|
echo Test 9 pass
|
|
end
|
|
# CHECK: Test 9 pass
|
|
|
|
# Test erasing variables in specific scope
|
|
|
|
set -eU __fish_test_universal_variables_variable_foo
|
|
set -g __fish_test_universal_variables_variable_foo bar
|
|
begin
|
|
set -l __fish_test_universal_variables_variable_foo baz
|
|
set -eg __fish_test_universal_variables_variable_foo
|
|
end
|
|
|
|
if set -q __fish_test_universal_variables_variable_foo
|
|
echo Test 10 fail
|
|
else
|
|
echo Test 10 pass
|
|
end
|
|
# CHECK: Test 10 pass
|
|
|
|
set __fish_test_universal_variables_variable_foo abc def
|
|
set -e __fish_test_universal_variables_variable_foo[1]
|
|
if test $__fish_test_universal_variables_variable_foo '=' def
|
|
echo Test 11 pass
|
|
else
|
|
echo Test 11 fail
|
|
end
|
|
# CHECK: Test 11 pass
|
|
|
|
# Test combinations of export and scope
|
|
|
|
set -ge __fish_test_universal_variables_variable_foo
|
|
set -Ue __fish_test_universal_variables_variable_foo
|
|
set -Ux __fish_test_universal_variables_variable_foo bar
|
|
set __fish_test_universal_variables_variable_foo baz
|
|
if test (/bin/sh -c 'echo $__fish_test_universal_variables_variable_foo') = baz -a ($FISH -c 'echo $__fish_test_universal_variables_variable_foo') = baz
|
|
echo Test 12 pass
|
|
else
|
|
echo Test 12 fail
|
|
end
|
|
# CHECK: Test 12 pass
|
|
|
|
set -Ue __fish_test_universal_variables_variable_foo
|
|
|
|
# Should no longer be in environment (#2046)
|
|
env | string match '__fish_test_universal_variables_variable_foo=*'
|
|
|
|
set -Ux __fish_test_universal_variables_variable_foo bar
|
|
set -U __fish_test_universal_variables_variable_foo baz
|
|
if test (/bin/sh -c 'echo $__fish_test_universal_variables_variable_foo') = baz -a ($FISH -c 'echo $__fish_test_universal_variables_variable_foo') = baz
|
|
echo Test 13 pass
|
|
else
|
|
echo Test 13 fail
|
|
end
|
|
# CHECK: Test 13 pass
|
|
|
|
set -Ux __fish_test_universal_variables_variable_foo bar
|
|
set -u __fish_test_universal_variables_variable_foo bar
|
|
if test (/bin/sh -c 'echo $__fish_test_universal_variables_variable_foo') = '' -a ($FISH -c 'echo $__fish_test_universal_variables_variable_foo') = bar
|
|
echo Test 14 pass
|
|
else
|
|
echo Test 14 fail
|
|
end
|
|
# CHECK: Test 14 pass
|
|
|
|
set -Ux __fish_test_universal_variables_variable_foo bar
|
|
set -Uu __fish_test_universal_variables_variable_foo baz
|
|
if test (/bin/sh -c 'echo $__fish_test_universal_variables_variable_foo') = '' -a ($FISH -c 'echo $__fish_test_universal_variables_variable_foo') = baz
|
|
echo Test 15 pass
|
|
else
|
|
echo Test 15 fail
|
|
end
|
|
# CHECK: Test 15 pass
|
|
|
|
set -eU __fish_test_universal_variables_variable_foo
|
|
function watch_foo --on-variable __fish_test_universal_variables_variable_foo
|
|
echo Foo change detected
|
|
end
|
|
|
|
set -U __fish_test_universal_variables_variable_foo 1234
|
|
# CHECK: Foo change detected
|
|
set -eU __fish_test_universal_variables_variable_foo
|
|
# CHECK: Foo change detected
|
|
# WTF set -eg __fish_test_universal_variables_variable_foo
|
|
|
|
functions -e watch_foo
|
|
|
|
# test erasing variables without a specified scope
|
|
|
|
set -g test16res
|
|
set -U __fish_test_universal_variables_variable_foo universal
|
|
set -g __fish_test_universal_variables_variable_foo global
|
|
|
|
begin
|
|
set -l __fish_test_universal_variables_variable_foo blocklocal
|
|
|
|
function test16
|
|
set -l __fish_test_universal_variables_variable_foo function
|
|
begin
|
|
set -l __fish_test_universal_variables_variable_foo functionblock
|
|
set test16res $test16res $__fish_test_universal_variables_variable_foo
|
|
|
|
# This sequence seems pointless but it's really verifying that we
|
|
# succesfully expose higher scopes as we erase the closest scope.
|
|
set -e __fish_test_universal_variables_variable_foo
|
|
set test16res $test16res $__fish_test_universal_variables_variable_foo
|
|
|
|
set -e __fish_test_universal_variables_variable_foo
|
|
set test16res $test16res $__fish_test_universal_variables_variable_foo
|
|
|
|
set -e __fish_test_universal_variables_variable_foo
|
|
set test16res $test16res $__fish_test_universal_variables_variable_foo
|
|
|
|
set -e __fish_test_universal_variables_variable_foo
|
|
set -q __fish_test_universal_variables_variable_foo
|
|
and set test16res $test16res $__fish_test_universal_variables_variable_foo
|
|
end
|
|
|
|
set -q __fish_test_universal_variables_variable_foo
|
|
and echo __fish_test_universal_variables_variable_foo should set after test16 inner begin..end
|
|
end
|
|
|
|
test16
|
|
set test16res $test16res $__fish_test_universal_variables_variable_foo
|
|
end
|
|
# CHECK: count:5 content:[functionblock function global universal blocklocal]
|
|
|
|
set -q __fish_test_universal_variables_variable_foo
|
|
and echo __fish_test_universal_variables_variable_foo should set after test16 outer begin..end
|
|
|
|
echo count:(count $test16res) "content:[$test16res]"
|
|
if test (count $test16res) = 5 -a "$test16res" = "functionblock function global universal blocklocal"
|
|
echo Test 16 pass
|
|
else
|
|
echo Test 16 fail
|
|
end
|
|
# CHECK: Test 16 pass
|
|
|
|
# Test that shadowing with a non-exported variable works
|
|
set -gx __fish_test_env17 UNSHADOWED
|
|
env | string match '__fish_test_env17=*'
|
|
# CHECK: __fish_test_env17=UNSHADOWED
|
|
|
|
function __fish_test_shadow
|
|
set -l __fish_test_env17
|
|
env | string match -q '__fish_test_env17=*'; or echo SHADOWED
|
|
end
|
|
__fish_test_shadow
|
|
# CHECK: SHADOWED
|
|
|
|
# Test that the variable is still exported (#2611)
|
|
env | string match '__fish_test_env17=*'
|
|
# CHECK: __fish_test_env17=UNSHADOWED
|
|
|
|
# Test that local exported variables are copied to functions (#1091)
|
|
function __fish_test_local_export
|
|
echo $var
|
|
set var boo
|
|
echo $var
|
|
end
|
|
set -lx var wuwuwu
|
|
__fish_test_local_export
|
|
# CHECK: wuwuwu
|
|
# CHECK: boo
|
|
echo $var
|
|
# CHECK: wuwuwu
|
|
|
|
# Test that we don't copy local-exports to blocks.
|
|
set -lx var foo
|
|
begin
|
|
echo $var
|
|
# CHECK: foo
|
|
set var bar
|
|
echo $var
|
|
# CHECK: bar
|
|
end
|
|
echo $var # should be "bar"
|
|
# CHECK: bar
|
|
|
|
# clear for other shells
|
|
set -eU __fish_test_universal_variables_variable_foo
|
|
|
|
# Test behavior of universals on startup (#1526)
|
|
echo Testing Universal Startup
|
|
# CHECK: Testing Universal Startup
|
|
set -U testu 0
|
|
$FISH -c 'set -U testu 1'
|
|
echo $testu
|
|
# CHECK: 1
|
|
$FISH -c 'set -q testu; and echo $testu'
|
|
# CHECK: 1
|
|
|
|
$FISH -c 'set -U testu 2'
|
|
echo $testu
|
|
# CHECK: 2
|
|
$FISH -c 'set -q testu; and echo $testu'
|
|
# CHECK: 2
|
|
|
|
$FISH -c 'set -e testu'
|
|
set -q testu
|
|
or echo testu undef in top level shell
|
|
# CHECK: testu undef in top level shell
|
|
$FISH -c 'set -q testu; or echo testu undef in sub shell'
|
|
# CHECK: testu undef in sub shell
|
|
|
|
# test SHLVL
|
|
# use a subshell to ensure a clean slate
|
|
env SHLVL= $FISH -c 'echo SHLVL: $SHLVL; $FISH -c \'echo SHLVL: $SHLVL\''
|
|
# CHECK: SHLVL: 1
|
|
# CHECK: SHLVL: 2
|
|
|
|
# exec should decrement SHLVL
|
|
env SHLVL= $FISH -c 'echo SHLVL: $SHLVL; exec $FISH -c \'echo SHLVL: $SHLVL\''
|
|
# CHECK: SHLVL: 1
|
|
# CHECK: SHLVL: 1
|
|
|
|
# garbage SHLVLs should be treated as garbage
|
|
env SHLVL=3foo $FISH -c 'echo SHLVL: $SHLVL'
|
|
# CHECK: SHLVL: 1
|
|
|
|
# whitespace is allowed though (for bash compatibility)
|
|
env SHLVL="3 " $FISH -c 'echo SHLVL: $SHLVL'
|
|
env SHLVL=" 3" $FISH -c 'echo SHLVL: $SHLVL'
|
|
# CHECK: SHLVL: 4
|
|
# CHECK: SHLVL: 4
|
|
|
|
# Test transformation of inherited variables
|
|
env DISPLAY="localhost:0.0" $FISH -c 'echo Elements in DISPLAY: (count $DISPLAY)'
|
|
# CHECK: Elements in DISPLAY: 1
|
|
|
|
# We can't use PATH for this because the global configuration will modify PATH
|
|
# based on /etc/paths and /etc/paths.d.
|
|
# Exported arrays are colon delimited; they are automatically split on colons if they end in PATH.
|
|
set -gx FOO one two three four
|
|
set -gx FOOPATH one two three four
|
|
$FISH -c 'echo Elements in FOO and FOOPATH: (count $FOO) (count $FOOPATH)'
|
|
# CHECK: Elements in FOO and FOOPATH: 1 4
|
|
|
|
# some must use colon separators!
|
|
set -lx MANPATH man1 man2 man3
|
|
env | grep '^MANPATH='
|
|
# CHECK: MANPATH=man1:man2:man3
|
|
|
|
# ensure we don't escape space and colon values
|
|
set -x DONT_ESCAPE_COLONS 1: 2: :3:
|
|
env | grep '^DONT_ESCAPE_COLONS='
|
|
# CHECK: DONT_ESCAPE_COLONS=1: 2: :3:
|
|
|
|
set -x DONT_ESCAPE_SPACES '1 ' '2 ' ' 3 ' 4
|
|
env | grep '^DONT_ESCAPE_SPACES='
|
|
# CHECK: DONT_ESCAPE_SPACES=1 2 3 4
|
|
|
|
set -x DONT_ESCAPE_COLONS_PATH 1: 2: :3:
|
|
env | grep '^DONT_ESCAPE_COLONS_PATH='
|
|
# CHECK: DONT_ESCAPE_COLONS_PATH=1::2:::3:
|
|
|
|
|
|
# Path universal variables
|
|
set -U __fish_test_path_not a b c
|
|
set -U __fish_test_PATH 1 2 3
|
|
echo "$__fish_test_path_not $__fish_test_PATH" $__fish_test_path_not $__fish_test_PATH
|
|
# CHECK: a b c 1:2:3 a b c 1 2 3
|
|
|
|
set --unpath __fish_test_PATH $__fish_test_PATH
|
|
echo "$__fish_test_path_not $__fish_test_PATH" $__fish_test_path_not $__fish_test_PATH
|
|
# CHECK: a b c 1 2 3 a b c 1 2 3
|
|
|
|
set --path __fish_test_path_not $__fish_test_path_not
|
|
echo "$__fish_test_path_not $__fish_test_PATH" $__fish_test_path_not $__fish_test_PATH
|
|
# CHECK: a:b:c 1 2 3 a b c 1 2 3
|
|
|
|
set --path __fish_test_PATH $__fish_test_PATH
|
|
echo "$__fish_test_path_not $__fish_test_PATH" $__fish_test_path_not $__fish_test_PATH
|
|
# CHECK: a:b:c 1:2:3 a b c 1 2 3
|
|
|
|
set -U __fish_test_PATH 1:2:3
|
|
echo "$__fish_test_PATH" $__fish_test_PATH
|
|
# CHECK: 1:2:3 1 2 3
|
|
|
|
set -e __fish_test_PATH
|
|
set -e __fish_test_path_not
|
|
|
|
set -U --path __fish_test_path2 a:b
|
|
echo "$__fish_test_path2" $__fish_test_path2
|
|
# CHECK: a:b a b
|
|
|
|
set -e __fish_test_path2
|
|
|
|
# Test empty uvars (#5992)
|
|
set -Ux __fish_empty_uvar
|
|
set -Uq __fish_empty_uvar
|
|
echo $status
|
|
# CHECK: 0
|
|
$FISH -c 'set -Uq __fish_empty_uvar; echo $status'
|
|
# CHECK: 0
|
|
env | grep __fish_empty_uvar
|
|
# CHECK: __fish_empty_uvar=
|
|
|
|
# Variable names in other commands
|
|
# Test invalid variable names in loops (#5800)
|
|
for a,b in y 1 z 3
|
|
echo $a,$b
|
|
end
|
|
# CHECKERR: {{.*}} for: Variable name 'a,b' is not valid. See `help identifiers`.
|
|
# CHECKERR:
|
|
# CHECKERR: for a,b in y 1 z 3
|
|
# CHECKERR: ^
|
|
|
|
|
|
# Global vs Universal Unspecified Scopes
|
|
set -U __fish_test_global_vs_universal universal
|
|
echo "global-vs-universal 1: $__fish_test_global_vs_universal"
|
|
# CHECK: global-vs-universal 1: universal
|
|
|
|
set -g __fish_test_global_vs_universal global
|
|
echo "global-vs-universal 2: $__fish_test_global_vs_universal"
|
|
# CHECK: global-vs-universal 2: global
|
|
|
|
|
|
set __fish_test_global_vs_universal global2
|
|
echo "global-vs-universal 3: $__fish_test_global_vs_universal"
|
|
# CHECK: global-vs-universal 3: global2
|
|
|
|
set -e -g __fish_test_global_vs_universal
|
|
echo "global-vs-universal 4: $__fish_test_global_vs_universal"
|
|
# CHECK: global-vs-universal 4: universal
|
|
|
|
set -e -U __fish_test_global_vs_universal
|
|
echo "global-vs-universal 5: $__fish_test_global_vs_universal"
|
|
# CHECK: global-vs-universal 5:
|
|
|
|
# Export local variables from all parent scopes (issue #6153).
|
|
function func; echo $local; end
|
|
set -lx local outer
|
|
func
|
|
# CHECK: outer
|
|
begin
|
|
func
|
|
# CHECK: outer
|
|
|
|
set -lx local inner
|
|
begin; func; end
|
|
# CHECK: inner
|
|
end
|
|
|
|
# Skip importing universal variables (#5258)
|
|
while set -q EDITOR; set -e EDITOR; end
|
|
set -Ux EDITOR emacs -nw
|
|
# CHECK: $EDITOR: not set in global scope
|
|
# CHECK: $EDITOR: set in universal scope, exported, with 2 elements
|
|
$FISH -c 'set -S EDITOR' | string match -r -e 'global|universal'
|
|
|
|
# When the variable has been changed outside of fish we accept it.
|
|
# CHECK: $EDITOR: set in global scope, exported, with 1 elements
|
|
# CHECK: $EDITOR: set in universal scope, exported, with 2 elements
|
|
sh -c "EDITOR='vim -g' $FISH -c "'\'set -S EDITOR\'' | string match -r -e 'global|universal'
|
|
|
|
true
|