0

This is my foo.bat file:

if 0==0 (
set foo=abc
echo "%foo%"
)

Windows (10 Pro Build 19043)

Call it with cmd.exe /C foo.bat, it prints "abc".

WSL (2, Ubuntu-20.04)

Call it with cmd.exe /C foo.bat it prints "".


Things I checked

  • SETLOCAL EnableDelayedExpansion changes nothing
  • cmd.exe in WSL is /mnt/c/Windows/system32/cmd.exe
  • when you remove the enclosing if, it works
Gerhard
  • 22,678
  • 7
  • 27
  • 43
user3093235
  • 397
  • 2
  • 12
  • 4
    It shouldn't work in Windows - you're setting and using a variable inside of the same set of parentheses, so you'd need to use delayed expansion (`echo "!foo!"`) for the value to display correctly. I suspect that your Windows environment already had `%foo%` set and the script is simply displaying that value. – SomethingDark Jan 28 '22 at 15:42
  • If I change the value from "abc" to "xyz" it prints "xyz" in Windows. So the explanation of a preset env variable, can't be right. Also, I did write, that I tried it with `SETLOCAL EnableDelayedExpansion`. Finally, if I try `echo "!foo!"`, it just prints that string. – user3093235 Jan 28 '22 at 15:59
  • 1
    Only `setlocal EnableDElayedExpansion` won't help, you need to replace `%foo%` by `!foo!` to actually apply delayed expansion. To show the true variable value replace the `echo` statement by `set foo`. Also note that `setlocal` only works in a batch file… – aschipfl Jan 28 '22 at 15:59
  • Thanks. Doing both `SETLOCAL EnableDelayedExpansion` and `echo "!foo!"` makes it work now in both cases. – user3093235 Jan 28 '22 at 16:07
  • @aschipfl Will you post as the answer? I was just about to start work on it when I noticed it was solved in the comments :-). Thanks! – NotTheDr01ds Jan 28 '22 at 16:19
  • There is no good answer yet, why there is a disparity between WSL and Windows behaviour though. – user3093235 Jan 28 '22 at 16:34
  • Put `set foo=` as the very first command in your script to ensure `foo` is not defined at the beginning, then try again; you shouldn't notice any difference then… – aschipfl Jan 28 '22 at 16:45
  • Too late, @NotTheDr01ds, the question is meanwhile closed as a duplicate, but the linked thread fully covers this post anyway… – aschipfl Jan 28 '22 at 16:51
  • 2
    @user3093235 Does the following explain the difference for you? The *first* time I run `foo.bat` in CMD (without calling a subshell), it prints "". The *second* time (and ever after), `foo` has been defined by the first invocation and prints `"abc"`. When you launch from WSL, *every* CMD invocation results in a fresh CMD instance, so `foo` is *always* undefined. As aschipfl said, if you ran `foo.bat` even once in the parent CMD, then `cmd.exe /C foo.bat` is going to propagate `foo` to the subprocess. – NotTheDr01ds Jan 28 '22 at 17:07
  • 2
    Yes I can see now, how I could have messed that up. I assumed foo to be only defined locally (non-persistently). I don't write .bat scripts very often... Thanks to all for the help. – user3093235 Jan 28 '22 at 17:10
  • @user3093235 Glad we got it sorted out! And no worries - I haven't done much CMD scripting in a couple of decades either. It really seems to be the difference in variable scope -- CMD assumes variables are exported unless defined `SETLOCAL`, while Linux shells assume they are local unless `export`ed. Even so, a Linux process in WSL doesn't (by default) pass exported environment variables to a Windows process (such as CMD), nor does it inherit environment variables when called from a Windows process. Exception -- This can be overcome using `WSLENV`. – NotTheDr01ds Jan 28 '22 at 20:21

0 Answers0